Search code examples
node.jsapigmail-apidelegationgoogle-admin-sdk

API Gmail in NodeJS: (node:14592) UnhandledPromiseRejectionWarning: Error: Delegation denied


I'm in real trouble with GMAIL API, here is my error:

(node:14592) UnhandledPromiseRejectionWarning: Error: Delegation denied for ADMIN_EMAIL

Here is my code, I want to change my signature with the gsuits admin of the domain at first. When i tried to just check and prompt my gmail information account, it's okay, but when I want to modify the signature, the error appeared. I set scopes in Wide-delegation domain with the ID service account and download credentials.JSON

const {google} = require('googleapis');

const keys = require('./credentials.json');
const {JWT} = require('google-auth-library');

// If modifying these scopes, delete token.json.
const SCOPES = ['https://www.googleapis.com/auth/admin.directory.user',
    'https://www.googleapis.com/auth/gmail.settings.basic',
    'https://www.googleapis.com/auth/gmail.settings.sharing',
    'https://www.googleapis.com/auth/gmail.modify',
    'https://mail.google.com',
    'https://www.googleapis.com/auth/gmail.compose',
    'https://www.googleapis.com/auth/gmail.readonly',
];

async function main() {
    const client = new JWT(
        {
            email: keys.client_email,
            key: keys.private_key,
            subject: ADMIN_EMAIL,
            scopes: SCOPES,
        }
    );
    const url = `https://dns.googleapis.com/dns/v1/projects/${keys.project_id}`;
    listUsers(client);
}

main();

/**
 * Lists all users in the domain and check if he's my email.
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
function listUsers(auth) {
    const service = google.admin({version: 'directory_v1', auth});
    service.users.list({
        customer: 'my_customer',
        maxResults: 50,
        orderBy: 'email',
    }, (err, res) => {
        if (err) return console.error('The API returned an error:', err.message);

        const users = res.data.users;
        if (users.length) {
            console.log('Users:');
            users.forEach((user) => {
                //credentials

                //changer signature
                if (user.primaryEmail && user.primaryEmail === MY_EMAIL) {
                    /*const client = new JWT(
                        {
                            email: keys.client_email,
                            key: keys.private_key,
                            subject: ADMIN_EMAIL,
                            scopes: SCOPES,
                        }
                    );*/
                    //client.subject = user.primaryEmail;
                    const gmail = google.gmail({version: 'v1', auth});
                    gmail.users.settings.delegates.list({userId:user.primaryEmail});
                    gmail.users.settings.sendAs.update({
                        userId: user.primaryEmail,
                        sendAsEmail: user.primaryEmail,
                        fields: 'signature',
                        resource: {
                            signature: SIGNATURE
                        }
                    });
                } else {
                    console.log('Error: Not found');
                }
            });
        } else {
            console.log('No users found.');
        }
    });
}

Edit: I found my misstakes, like ziganotschka said, I need to create a new JWT client. Here is the new function listUsers:

function listUsers(auth) {
const service = google.admin({version: 'directory_v1', auth});
service.users.list({
    customer: 'my_customer',
    maxResults: 50,
    orderBy: 'email',
}, (err, res) => {
    if (err) return console.error('The API returned an error:', err.message);

    const users = res.data.users;
    if (users.length) {
        console.log('Users:');
        users.forEach((user) => {
            //changer signature
            if (user.primaryEmail && (user.primaryEmail === MY_SIGNATURE)) {
                const client = new JWT(
                    {
                        email: keys.client_email,
                        key: keys.private_key,
                        subject: user.primaryEmail,
                        scopes: SCOPES,
                    }
                );
                client.subject = user.primaryEmail;
                const gmail = google.gmail({version: 'v1', auth: client});
                gmail.users.settings.delegates.list({userId:user.primaryEmail});
                gmail.users.settings.sendAs.update({
                    userId: user.primaryEmail,
                    sendAsEmail: user.primaryEmail,
                    fields: 'signature',
                    resource: {
                        signature: SIGNATURE
                    }
                });
            } else {
                console.log('Error: Not found');
            }
        });
    } else {
        console.log('No users found.');
    }
});

}


Solution

  • To change a user's signature you have to impersonate the user

    • As you are already doing correctly, for creating / updating user signatures you have to use the service account with domain-wide delegation
    • However, if the service acocunt impersonates the admin, you will receive the error Delegation denied for ADMIN_EMAIL
    • This is because the admin is not authorized to change any siganture other than his own
    • So instead you need to create within your loop (users.forEach((user)) a new JWT client - with the respective user email as subject - for each user