How to send a message successfully using the new Gmail REST API?
Asked Answered
S

5

34

I'm currently trying to test the new Gmail REST API.

In the API Explorer it is possible to authorize requests using OAuth 2.0 and to execute a request, i.e. send a message.

First I authorized. enter image description here

I'm using the following test data (and of course I used a valid to email address):

{    
   "raw": "c2VuZGluZyBhIG1haWwgdXNpbmcgR21haWwgUkVTVCBBUEk=",  
   "payload": { 
     "headers": [ 
       { "name": "to",      "value": "[email protected]"   }, 
       { "name": "from",    "value": "[email protected]" }, 
       { "name": "subject", "value": "Test Gmail REST API"  } 
     ],
     "mimeType": "text/plain" 
   }
}

I also get a 200 OK and the following result back, which looks fine.

{
  "id": "146dee391881b35b",
  "threadId": "146dee391881b35b",
}

However, the mail will not be sent successfully and I can find an message from [email protected] in the inbox instead;: "An error occurred, your message has not been sent."

enter image description here

Questions:
1. Did someone test this successfully?
2. Do I have to add some other parameter to get this running?



EDIT: There are 2 different HTTP request methods,

  1. the Upload URI for media upload requests, and
  2. the Metadata URI for metadata-only requests

The API Explorer currently supports metadata requests only, which means plain-text messages without attachment, and this is what I'm trying to do.

Sari answered 27/6, 2014 at 20:38 Comment(3)
sure, of course I authorized the request first, else I guess I would not get a 200 OK back...Sari
@Taifun, How did you created the RFC 2822 string, Is there any libraries or hard coded it, any examples?Vizard
@Vizard This depends on your favorite programming language. see my answer below how to web-safe base64 encode the complete messageSari
S
65

got it!

after reading the RFC 2822 specification I found out, that the complete message needs to be passed in the raw parameter, see the example:

From: John Doe <[email protected]> 
To: Mary Smith <[email protected]> 
Subject: Saying Hello 
Date: Fri, 21 Nov 1997 09:55:06 -0600 
Message-ID: <[email protected]>

This is a message just to say hello. So, "Hello".

So after base64 encoding the complete message, passing it in the raw parameter without using any other parameter, it works fine.

Edit 1:
As @Amit mentioned, it must be web-safe base64 encoded, see also https://code.google.com/p/stringencoders/wiki/WebSafeBase64

So to convert the base64 alpha into a format that is "web-safe" the following changes are recommended:

+ --> - (char 62, plus to dash)
/ --> _ (char 63, slash to underscore)
= --> * padding

To only convert + to - and /to _ was sufficient for me.

Edit 2:
To answer the question of @Hjulle here an example: you only need the userId and in the request body the raw parameter. Let's assume, your email address is [email protected]

First Base64 encode the complete message (see above) using an online encoder and you get this string:

RnJvbTogSm9obiBEb2UgPGpkb2VAbWFjaGluZS5leGFtcGxlPiAKVG86IE1hcnkgU21pdGggPG1h
cnlAZXhhbXBsZS5uZXQ+IApTdWJqZWN0OiBTYXlpbmcgSGVsbG8gCkRhdGU6IEZyaSwgMjEgTm92
IDE5OTcgMDk6NTU6MDYgLTA2MDAgCk1lc3NhZ2UtSUQ6IDwxMjM0QGxvY2FsLm1hY2hpbmUuZXhh
bXBsZT4KClRoaXMgaXMgYSBtZXNzYWdlIGp1c3QgdG8gc2F5IGhlbGxvLiBTbywgIkhlbGxvIi4=

Now convert + to - and /to _ and you get

RnJvbTogSm9obiBEb2UgPGpkb2VAbWFjaGluZS5leGFtcGxlPiAKVG86IE1hcnkgU21pdGggPG1h
cnlAZXhhbXBsZS5uZXQ-IApTdWJqZWN0OiBTYXlpbmcgSGVsbG8gCkRhdGU6IEZyaSwgMjEgTm92
IDE5OTcgMDk6NTU6MDYgLTA2MDAgCk1lc3NhZ2UtSUQ6IDwxMjM0QGxvY2FsLm1hY2hpbmUuZXhh
bXBsZT4KClRoaXMgaXMgYSBtZXNzYWdlIGp1c3QgdG8gc2F5IGhlbGxvLiBTbywgIkhlbGxvIi4=

Now pass this in the raw parameter of the API Explorer.

Sari answered 27/6, 2014 at 21:35 Comment(8)
url encoding required. #22129289Demurral
gist.github.com/AkashkumarDev/20ab002e7f5785ae778e any idea where is problem ?Ingrowing
@akdev for questions please start a new question instead of commenting here. thank you.Sari
#25396963Ingrowing
Doesn't work for me https://mcmap.net/q/451249/-gmail-api-emails-bouncingDesexualize
@taifun, my message sending successfully. but, how to add threadId and labelId while sending the message?Dwaynedweck
@users4393829 please ask a new questionSari
already did. #34961183Dwaynedweck
G
3

This worked for me

Url: https://www.googleapis.com/upload/gmail/v1/users/me/messages/send (POST Method)

InHeaders:- "Authorization " : "Bearer ya29.Il-iBylW9AUr6V0QO72ryo17r7hf8i5zh8dU63ZjDNaxAApumh6T7lh20my_DQZomtL_qokZnJEgapYN20LmdlG6lFbqGASL5lqFAKnOoUtZA992JwOlUQxMVW6_Yto7jQ", "Content-Type" : "message/rfc822"

InBody:-

{"raw": "From: <[email protected]> 
To: <[email protected]> 
Subject: Saying Hello
This is a message just to say hello. So, "Hello"."}
Groark answered 21/10, 2019 at 11:28 Comment(0)
R
2

Note: This is a PHP specific answer, but I'm sure some of you will find it useful.

In case you're struggling with setting up the raw data correctly in PHP as I did, using PHPMailer would make things cleaner and easier for you.

After including the library in your code (if you use composer, just add "phpmailer/phpmailer": "~5.2" in the require section of your composer.json), you set the basic details:

$mail = new PHPMailer();
$mail->From = 'FROM_EMAIL';
$mail->FromName = 'FROM_NAME';
$mail->addAddress('TO_EMAIL','TO_NAME');
$mail->Subject = 'EMAIL_SUBJECT';
$mail->Body = 'EMAIL_BODY';
$mail->preSend(); 
$mime = $mail->getSentMIMEMessage();

Now you can base64 encode the $mime to get the raw string for the Gmail API. Use this instead of simple base64_encode, in order to get a valid web safe encoded string. rtrim(strtr(base64_encode($mime), '+/', '-_'), '=');

Rojo answered 16/5, 2016 at 14:18 Comment(4)
the question is : "using the new Gmail REST API?"... so why talk about PHPMailer...Hermes
@Hermes because I spent two days researching how to implement this in PHP and I figured why not share my findings on this lovely knowledge sharing platform, with people who, like me, ran onto this answer because they couldn't find what they're looking for. Note the disclaimer at the top. Happy Monday!Rojo
still not in the right subject... i can post how to send and email with python then java too and people looking for the real subject answer will be so happy to find this here.Hermes
This does answer the question in a sense that you get a fully prepared message built by PHPMailer and then use Gmail API to send it. The idea is to get some 3rd party library and not deal with the raw settings of the message.Tango
G
1

you could also send it as a messsage. e.g.

POST https://www.googleapis.com/upload/gmail/v1/users/me/messages/send


Headers:-
"Authorization":"Bearer <Your-Token>", 
"Content-Type" : "message/rfc822"

Body:
"From: <[email protected]> 
To: <[email protected]> 
Subject: Saying Hello
This is a message just to say hello. So, 'Hello'"
Gd answered 6/8, 2022 at 14:17 Comment(1)
In fact, this is correct answer. The answer by Taifun that is currently of the highest score is verbose, not to the point, and is inferior to this answer. This shows the problem of the legacy scoring system of SO.Rigamarole
C
0

This is what worked for me...

Instead of manually creating the email message and encoding it entirely as base64, we need to follow the RFC 2822 format for email messages and then encode specific parts.

So, I encoded only the message body as base64 (and left the headers in clear text).

import fetch from 'node-fetch';

function encode(str, urlSafe = false) {
    const encoded = Buffer.from(str).toString('base64');
    return urlSafe ? encoded.replace(/\+/g, '-').replace(/\//g, '_') : encoded;
}

function createEmail(sender, receiver, subject, message) {
    const emailLines = [];
    emailLines.push(`From: ${sender}`);
    emailLines.push(`To: ${receiver}`);
    emailLines.push(`Subject: ${subject}`);
    emailLines.push('');
    emailLines.push(message); // Message body

    const email = emailLines.join('\r\n');
    const encodedEmail = encode(email);

    return encodedEmail;
}

export default async function sendEmailWithGmailAPI({ sender, receiver, subject, message }, { auth }) {
    const { access_token } = await auth.getToken();
    if (!receiver || !receiver.includes('@')) {
        throw new Error('Invalid receiver email address');
    }

    const rawMessage = createEmail(sender, receiver, subject, message);

    const response = await fetch(`https://gmail.googleapis.com/gmail/v1/users/me/messages/send`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            Authorization: `Bearer ${access_token}`,
        },
        body: JSON.stringify({
            raw: rawMessage,
        }),
    });

    const data = await response.json();
    return data;
}
Cannonball answered 8/12, 2023 at 7:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.