4

this is my barebones code. I want to send an email as one of the users of my domain. The email might be different every call.

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

function makeBody(to, from, subject, message) {
    const str = [
        'Content-Type: text/plain; charset="UTF-8"\n',
        'MIME-Version: 1.0\n',
        'Content-Transfer-Encoding: 7bit\n',
        'to: ', to, '\n',
        'from: ', from, '\n',
        'subject: ', subject, '\n\n',
        message,
    ].join('');

    return Buffer.from(str).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');
}

class MailProvider {
    gmail = google.gmail({
        version: 'v1',
        auth: new google.auth.GoogleAuth({
            keyFile: '../../assets/secrets/google.json', // See below
            scopes: [
                'https://mail.google.com/',
                'https://www.googleapis.com/auth/gmail.addons.current.action.compose',
                'https://www.googleapis.com/auth/gmail.compose',
                'https://www.googleapis.com/auth/gmail.modify',
                'https://www.googleapis.com/auth/gmail.send',
            ],
        }),
    });

    async sendMail(sendAs, sendTo) {
        return this.gmail.users.messages.send({
            userId: sendAs,
            requestBody: {
                raw: makeBody(sendTo, sendAs, 'Test subject', 'Test body'),
            },
        }).catch(console.error);
    }
}

new MailProvider().sendMail('noreply@mydomain.cz', 'akxe@seznam.cz');

Censored google.json:

{
  "type": "service_account",
  "project_id": "firm-aria-ID",
  "private_key_id": "ID",
  "private_key": "-----BEGIN PRIVATE KEY-----\n...key...\n-----END PRIVATE KEY-----\n",
  "client_email": "rita-sm@firm-aria-ID.iam.gserviceaccount.com",
  "client_id": "ID",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/rita-sm%40firm-aria-ID.iam.gserviceaccount.com"
}

I am getting the failedPrecondition error. I don't know what to do anymore... I am at this for more than one full day...

The error:

{
  // ...
  code: 400,
  errors: [
    {
      message: 'Precondition check failed.',
      domain: 'global',
      reason: 'failedPrecondition'
    }
  ]
}
Akxe
  • 9,694
  • 3
  • 36
  • 71
  • Did you try this: https://stackoverflow.com/questions/29327846/gmail-rest-api-400-bad-request-failed-precondition – Harshana Dec 03 '20 at 03:07
  • When you say "of your domain", do you mean a user member of your Google Workspace? If yes, did you setup Domain Wide Delegation? – John Hanley Dec 03 '20 at 03:46
  • @JohnHanley I am not sure. We are a company of 10 employees. I did use the admin account to create a service account for the api, what is the domain wide delegation. – Akxe Dec 03 '20 at 03:54
  • @HarshanaSerasinghe I did see that, but this is for JavaScript and I did not see same options to set them. – Akxe Dec 03 '20 at 03:56
  • See my answer for an example of Gmail with service account in Python: https://stackoverflow.com/a/55367351/8016720 You need to add anther step to your code to add the identity you want to impersonate. My example shows this step. See this document for details on Domain Wide Delegation: https://developers.google.com/admin-sdk/directory/v1/guides/delegation To impersonate a user in your Google Workspace domain requires Domain Wide Delegation for the service account. – John Hanley Dec 03 '20 at 04:06
  • You should set up a service account with domain wide dedication. – Linda Lawton - DaImTo Dec 03 '20 at 07:05
  • Have you checked the documentation on delegation? What did you mean on the comment " I did see that, but this is for JavaScript and I did not see same options to set them" ? – Kessy Dec 03 '20 at 08:32
  • @JohnHanley there is no method `with_subject` or similar. There is no subject property in `GoogleAuthOptions` either... – Akxe Dec 03 '20 at 12:34
  • @DaImTo I just did enable domain-wide delegation. I checked the "Enable G Suite Domain-wide Delegation" checkbox – Akxe Dec 03 '20 at 13:19
  • I do not develop in JavaScript, so I can only refer you to examples in other languages. – John Hanley Dec 03 '20 at 17:34
  • Make sure you have the gsuite admin set up the domain wide delegation properly. And that you are using node.js server sided and not client sided Javascript. – Linda Lawton - DaImTo Dec 03 '20 at 21:50
  • @DaImTo I did just that, I am using the `google-api-nodejs-client` and I have checked the button as stated in the previous comment. It is the correct one, right? – Akxe Dec 03 '20 at 22:37
  • Did you manage to solve it? If not, can you update on the issue? – Kessy Dec 09 '20 at 14:33
  • @Kessy I still did not manage to succeed, but to my knowledge, there might be better luck with MS exchange and its "graph API" – Akxe Dec 10 '20 at 19:04
  • Can you update on your progress? I have found two posts that may help you. [Stack Post](https://stackoverflow.com/questions/62848002/how-to-use-service-account-to-access-gmail-api-for-a-gsuite-email-account) and [API docs post](https://github.com/googleapis/google-api-nodejs-client/issues/2322) – Kessy Dec 15 '20 at 16:08

1 Answers1

0

You cannot use a service account for sending emails. You need to use 3 legged oauth and send emails on behalf of the enduser.

user835611
  • 2,309
  • 2
  • 21
  • 29