Gmail API: 400 Bad Request When Trying to Send an Email (PHP Code)

Gmail API: 400 bad request when trying to send an email (PHP code)

finally got to send Mails with your code:

I think you have misunderstood the GMail API a little bit.

To use it, you must authenticate to the API. To do this, there are two ways:

  • use OAuth - the Server redirects the user to google's servers, where they can login, grant permission to your app, and pass a token back to you
  • Service Accounts. These are a little bit more complicated:

    • First, you'll have to setup an app (done)
    • second, you'll have to setup a service account. This is how your app authenticates to google. you've done that, and the certificate you've got contains the private key to authenticate
    • third, the user needs to grant your application access to act on behalf of them. This is the point you haven't done yet.

So what you're currently trying is to send mails from the service account, but this is not an GMail Account.

The Developer Console uses the OAuth method, so there's no problem to try this.

Please also note: With regular GMail Accounts, you can not use 'Service Accounts'. You'll have to use OAuth.
To use Service Accounts, you need to be a Google Apps customer.

I won't conver OAuth authorization here, because it's completely different, and there are many examples out there.

To grant your Service Account Permissions to send mails on behalf of your GMails/Google Apps accounts, please follow
this document. For One or More API Scopes, you'll have to enter
https://mail.google.com/,https://www.googleapis.com/auth/gmail.modify,https://www.googleapis.com/auth/gmail.compose,https://www.googleapis.com/auth/gmail.send.

After you've setup this, it's possible to send mails, just modify the code as follows:

$results = $service->users_messages->send("me", $msg);

won't work, because 'me' referrs to the service account, which can't send mail (see above).
Replace me with the user id (mail-address) of the account from which the mails should be send.:

$results = $service->users_messages->send("senders_mail@domain.com", $msg);

Then, you'll need to add

$cred->sub = 'senders_mail@domain.com';

below

$cred = new \Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/gmail.send', 'https://www.googleapis.com/auth/gmail.compose'),
$key
);

Please also note that $message should be $msg in the try...catch-Block.

Below, you'll find the the complete, working code for me:

<?php
require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php');
$client_id = '*censored*.apps.googleusercontent.com';
$service_account_name = '*censored*@developer.gserviceaccount.com';
$key_file_location = '/tmp/apiKey.p12';

$userid_from='*censored*';
$client = new \Google_Client();
$client->setApplicationName("Client_Library_Examples");

//hmmm, really don't know whether these lines are necessary
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}

$key = file_get_contents($key_file_location);
$cred = new \Google_Auth_AssertionCredentials(
$service_account_name,
array('https://www.googleapis.com/auth/gmail.send', 'https://www.googleapis.com/auth/gmail.compose', 'https://www.googleapis.com/auth/gmail.modify','https://www.googleapis.com/auth/gmail.readonly'),
$key
);
$cred->sub=$userid_from; //<-- Important!
$client->setAssertionCredentials($cred);

if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}

//check if you want the validity of this string at: http://www.komeil.com/toolbox/base64decoder
//it is web safe base64 encoded email
$mime = "*censored*, same content as you posted, but another recipient ;-)";

$service = new \Google_Service_Gmail($client);

$msg = new \Google_Service_Gmail_Message();
$msg->setRaw($mime);

try {
$results = $service->users_messages->send($userid_from, $msg);
print 'Message with ID: ' . $results->id . ' sent.';
} catch (\Exception $e) {
print 'An error occurred: ' . $e->getMessage();
}

If there are any questions left, feel free to ask!

400 Bad Request on Gmail API with php

You should not be using a service account if you just want to access one account (your own). Service accounts are their own account and they're not Gmail accounts. They work well for APIs that don't need a user (e.g. maps, search) or when you are using a Google Apps for Work domain and want delegation enabled for all users in the domain (by domain admin, so you don't need individual user authorization).

You want to use standard oauth2 web auth flow. If you want to make sure it's usable offline (e.g. by some script/service/cron job) then make sure you add the offline flag on your oauth2 authorization web flow request and that'll make sure you get a permanent refresh token (can be used to request an access token). If you don't set offline, then it's an access token which is only good for an hour. See https://developers.google.com/gmail/api/auth/web-server for more details.



Related Topics



Leave a reply



Submit