Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attachment missing from message sent with Gmail API but only for recipient

Upon using the Gmail API in Javascript to send a message with an HTML body and a ~100KB PDF attachment, the attachment correctly appears attached to the message in the sender's Gmail Sent folder, but does not appear on the message for the recipient.

The API call is a POST to:

https://www.googleapis.com/upload/gmail/v1/users/me/messages/send?uploadType=media

The request body sent to the API is:

{
  "headers": {
    "Authorization": "Bearer authToken-removedForThisPost"
  },
  "method": "POST",
  "contentType": "message/rfc822",
  "contentLength": 134044,
  "payload": "exampleBelow",
  "muteHttpExceptions": true
}

This is what the payload looks like:

MIME-Version: 1.0
To: =?utf-8?B?TWlrZSBD?=<[email protected]>
CC: =?utf-8?B?TWlrZSBD?=<[email protected]>
BCC: =?utf-8?B??=<[email protected]>
From: =?utf-8?B?TWlrZSBxWXsd2lr?=<[email protected]>
Subject: =?utf-8?B?subjectLine-removedForThisPost?=
Content-Type: multipart/alternative; boundary=__boundary__

--__boundary__
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64

base64EncodedStringHere-removedForThisPost

--__boundary__
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: base64

base64EncodedStringHere-removedForThisPost

--__boundary__
Content-Type: application/pdf; name="File Name.pdf"
Content-Disposition: attachment; filename="File Name.pdf"
Content-Transfer-Encoding: base64

base64EncodedStringHere-removedForThisPost

--__boundary__--

Note: The Gmail API Uploading Attachments documentation states that when uploading a simple attachment (under 5MB) Content-Length is required. I made it so that my code produces an integer value of the total number of bytes of the PDF attachment. However, I noticed that Content-Length is not included in the payload.

I tried changing the multipart/alternative Content-Type for the message to multipart/mixed - this made it so that the PDF attachment IS correctly attached to the recipient's message, but the HTML body of the message is rendered as plain text (the HTML tags are shown) and there is an additional attachment called noname.html which includes the HTML content rendered as HTML.

I need to make it so that the email in the recipient's message has both an HTML-rendered body AND the PDF attachment.

Update: I uploaded examples of the raw email messages here. The sent message is on the left, and the received message is on the right.

like image 518
Employee Avatar asked Feb 05 '17 16:02

Employee


People also ask

Why are attachments not showing in Gmail?

Why can't I see attachments on Gmail? The messages with attachments may be collapsed behind newer messages, so you don't see the attachments, but they do show in the conversation list if you use the Default density and the paperclip icons should be visible in the list.

How do I find lost attachments in Gmail?

First, sign in to Gmail. Click on Trash icon or you can go to Settings > labels tab and after that tap the show link next to Trash label, this is how you can recover lost attachments.


1 Answers

Just replace:

Content-Type: multipart/alternative; boundary=__boundary__

for:

Content-Type: multipart/mixed; boundary=__boundary__

This is my full function written in JS

function createMimeMessage_(msg) {

var nl = "\n"; var boundary = "ctrlq_dot_org";

var mimeBody = [

"MIME-Version: 1.0",
"To: "      + msg.to.email,//+ encode_(msg.to.name) + "<" + msg.to.email + ">",
"Cc: "      + msg.cc.email,
"Bcc: "      + msg.bcc.email,
"From: "    + msg.from.email,//+ encode_(msg.from.name) + "<" + msg.from.email + ">",
"Subject: " + encode_(msg.subject), // takes care of accented characters
"In-Reply-To: " + (msg.reply_to || ""),
"References: " + (msg.reply_to || ""),

"Content-Type: multipart/mixed; boundary=" + boundary + nl,
"--" + boundary,

// "Content-Type: text/plain; charset=UTF-8",
// "Content-Transfer-Encoding: 7bit",
// "Content-Disposition: inline" + nl,
// msg.body.text + nl,
// "--" + boundary,

"Content-Type: text/html; charset=UTF-8",
"Content-Transfer-Encoding: base64" + nl,
new Buffer(msg.body.text).toString('base64') + nl,

];

for (var i = 0; i < msg.files.length; i++) {

var attachment = [
  "--" + boundary,
  "Content-Type: " + msg.files[i].mimeType + '; name="' + msg.files[i].fileName + '"',
  'Content-Disposition: attachment; filename="' + msg.files[i].fileName + '"',
  "Content-Transfer-Encoding: base64" + nl,
  msg.files[i].bytes
];

mimeBody.push(attachment.join(nl));

}

mimeBody.push("--" + boundary + "--"); //console.log(mimeBody);

return mimeBody.join(nl);

}

like image 179
Tiger developer Avatar answered Oct 08 '22 07:10

Tiger developer