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("[email protected]", $msg);

Then, you’ll need to add

$cred->sub = '[email protected]';

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!

Leave a Comment