When working with the Google APIs, it’s common to find yourself needing to bridge the functionalities of different services. In this blog post, I’ll walk you through how to create a draft email with an attachment stored in Google Drive using the GMail and Google Drive APIs in Node.js. We’ll start by discussing the pieces of code you already have and then move on to incorporating an attachment from Google Drive without the need to download it manually.
Current Setup for Creating Draft Emails without Attachments
You already have a functional setup for creating draft emails. Here’s the snippet you’re using to create a draft email without an attachment:
const res = await gmail.users.drafts.create({ userId: user.email, requestBody: { message: { raw: await createRawMessage(to, subject, htmlBody), }, }, });
The createRawMessage
function formats the necessary email headers and body into a raw format that Gmail can understand:
export async function createRawMessage(recipientEmail, subject, body) { const message = [ `Content-Type: text/html; charset="UTF-8"`, `to: ${recipientEmail}`, `subject: ${subject}\n`, body, ].join("\n"); return Buffer.from(message) .toString("base64") .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=+$/, ""); }
Why Not Just Use the fileId
from Google Drive?
Google’s APIs don’t allow for a direct reference of a fileId
from Google Drive inside an email draft in Gmail. This means you’ll have to download the file from Google Drive, base64 encode it, and then include it in the draft email.
Using Google Drive to Fetch the File
To fetch the file from Google Drive, you’ll need to use the Google Drive API. Here’s how you can do it in steps:
- Authorize with the Google Drive API: You’ll need proper OAuth credentials for accessing both the Drive and Gmail APIs.
- Retrieve the File: Use the Drive API to get the file’s content.
- Base64 Encode the File Content: Prepare the file for email attachment.
- Compose the Email with Attachment: Include the encoded file in the email draft.
Step-by-Step Code Implementation
- Authorize and Initialize APIs (Assuming you have set up OAuth2.0 credentials):
const {google} = require('googleapis'); const drive = google.drive('v3'); const gmail = google.gmail('v1'); const oauth2Client = new google.auth.OAuth2( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL ); // Set credentials oauth2Client.setCredentials({ access_token: 'YOUR_ACCESS_TOKEN', refresh_token: 'YOUR_REFRESH_TOKEN', });
- Fetch the File from Google Drive:
async function getFileContent(fileId) { const res = await drive.files.get({ fileId: fileId, alt: 'media', auth: oauth2Client, }, { responseType: 'arraybuffer' }); return Buffer.from(res.data, 'binary').toString('base64'); }
- Compose the
createRawMessage
Function to Include Attachment:
export async function createRawMessage(recipientEmail, subject, body, fileContent, fileName, mimeType) { const boundary = '----=_Part_0_1234567890.1234567890'; const message = [ `Content-Type: multipart/mixed; boundary="${boundary}"`, `to: ${recipientEmail}`, `subject: ${subject}\n\n`, `--${boundary}`, `Content-Type: text/html; charset="UTF-8"\n\n`, body, `--${boundary}`, `Content-Type: ${mimeType}; name="${fileName}"`, 'Content-Transfer-Encoding: base64', `Content-Disposition: attachment; filename="${fileName}"\n`, fileContent, `--${boundary}--`, ].join("\n"); return Buffer.from(message) .toString("base64") .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=+$/, ""); }
- Create the Draft Email with Attachment:
const fileId = 'YOUR_FILE_ID_FROM_GOOGLE_DRIVE'; const fileContent = await getFileContent(fileId); const fileMetadata = await drive.files.get({ fileId: fileId, fields: '*' }); const rawMessage = await createRawMessage( to, subject, htmlBody, fileContent, fileMetadata.data.name, fileMetadata.data.mimeType ); const res = await gmail.users.drafts.create({ userId: user.email, requestBody: { message: { raw: rawMessage, }, }, });
Explanation and Breakdown
- Authorization: You set up the authorization using OAuth2. This is crucial for securely interacting with Google APIs.
- Fetching the File: The
getFileContent
function retrieves the file content using the Drive API. Note that we useresponseType: 'arraybuffer'
to handle binary data.
- Creating the Raw Message: The
createRawMessage
function now constructs a MIME multipart email. This ensures that the email can handle both HTML content and file attachments.
- Creating the Draft: Finally, we create the draft in Gmail using the
gmail.users.drafts.create
method, passing the formatted raw email.
By following these steps, you avoid having to download the file manually and keep the process streamlined within your Node.js application. This approach leverages both Google Drive and GMail APIs efficiently to achieve the desired functionality.
Leave a Reply