Мне нужно составить черновик электронного письма с использованием API-интерфейсов GMail с вложением с идентификатором файла из Google Диска с использованием API-интерфейсов Google Диска.
У меня есть рабочий вызов API GMail, который создает черновик электронного письма (без вложения):
const res = await gmail.users.drafts.create({
userId: user.email,
requestBody: {
message: {
raw: await createRawMessage(to, subject, htmlBody),
},
},
});
Вот код моей функции createRawMessage
:
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(/=+$/, "");
}
Есть ли способ просто добавить fileId
с Google Диска? Я бы предпочел не загружать файл в Base64Encode, так как он уже находится на Google Диске, и у меня есть значок fileId
.
Кроме того, я не хочу использовать другую библиотеку, например NodeMailer.
Я рассмотрел, как отправлять электронные письма с вложениями (не создавая черновики), чтобы ссылаться на этот код в моей функции черновика, но мне не удалось найти образец, который извлекает файл с Google Диска. Единственные примеры требуют загрузки файла с Google Диска и последующего включения его в свойство raw параметра requestBody.message
API gmail.users.drafts.create
.
У меня это работает в скрипте Google Apps, но теперь я пытаюсь перенести эту функциональность в NodeJS.
ОБНОВЛЯТЬ: Вот код, который работает со скриптом Google Apps:
var attachments = [];
var file = DriveApp.getFileById(appDetails.resume_file_id);
attachments.push(file.getAs(file.getMimeType()));
var draft = GmailApp.createDraft(
`${contactDetails.contact_name} <${contactDetails.contact_email}>`,
`${appDetails.job_title} role @ ${appDetails.company}`,
textBody,
{
htmlBody: htmlBody,
attachments: attachments,
}
);```
В качестве простого подхода, как насчет следующей модификации? В этой модификации в htmlBody
вашего скрипта добавляется ссылка webViewLink файла на Google Диске. Для получения webViewLink используется Drive API.
Конечно, если вы уже знаете значения webViewLink
и name
файла, вы можете использовать их напрямую. В настоящее время использование Drive API не требуется.
Важным моментом является то, что в этом случае, чтобы открыть файл на стороне пользователя, необходимо поделиться файлом с пользователем. Пожалуйста, будьте осторожны.
Если вы тестируете этот скрипт, включите Drive API и добавьте область https://www.googleapis.com/auth/drive.metadata.readonly
к своим текущим областям.
const gmail = google.gmail({ version: "v1", auth }); // Please set your client
const drive = google.drive({ version: "v3", auth }); // Please set your client
// Please set your values.
const fileId = "###";
const user = { email: "###" };
const to = "###";
const subject = "sample subject";
const htmlBody = "sample HTML body.";
const { data: { name, webViewLink } } = await drive.files.get({ fileId, fields: "name,webViewLink" });
const res = await gmail.users.drafts.create({
userId: user.email,
requestBody: {
message: {
raw: await createRawMessage(
to,
subject,
htmlBody + `<div><a href = "${webViewLink}" target = "_blank"><span>${name}</span></a></div>`
),
},
},
});
console.info(res.data);
В этой модификации используется webViewLink
. Но если вы хотите прикрепить файл в виде двоичных данных, если файл не является файлом Документов Google (документы, таблицы, слайды и т. д.), вы можете прикрепить файл напрямую. Но если файл представляет собой файл Документов Google, его необходимо преобразовать в другой тип mimeType, поскольку на текущем этапе файлы Документов Google невозможно напрямую экспортировать с исходным типом mimeType. Пожалуйста, будьте осторожны с этим. Но по вашему вопросу я предположил, что это может быть не тот результат, которого вы ожидали.
Если этот подход не дает ожидаемого результата, укажите текущий сценарий this working in a Google Apps Script
из I have this working in a Google Apps Script, but now trying to migrate this functionality to NodeJS.
.
Из ответа ОП:
Я думал просто поместить webViewLink в тело, но на самом деле мне хотелось бы добавить вложение.
Я заметил, что ОП хотел прикрепить содержимое файла, не являющееся файлами Google Docs. В этом случае пример сценария выглядит следующим образом. В этом случае содержимое файла можно загрузить напрямую.
В этой модификации добавьте https://www.googleapis.com/auth/drive.readonly
для загрузки содержимого файла.
function getData(drive, fileId) {
return new Promise((resolve, reject) => {
drive.files.get(
{ fileId, alt: "media", supportsAllDrives: true },
{ responseType: "stream" },
function (err, { data }) {
if (err) {
return reject("The API returned an error: " + err);
}
let buf = [];
data.on("data", function (e) {
buf.push(e);
});
data.on("end", function () {
const buffer = Buffer.concat(buf);
resolve(buffer.toString("base64"));
});
}
);
});
}
async function createRawMessage(recipientEmail, subject, body, drive, fileId) {
const { data: { name, mimeType } } = await drive.files.get({ fileId, fields: "name,mimeType" });
const fileContent = await getData(drive, fileId);
// Ref: This is my answer. https://stackoverflow.com/a/53891937
const message = [
"MIME-Version: 1.0",
`to: ${recipientEmail}`,
`subject: ${subject}`,
"Content-Type: multipart/mixed; boundary=boundary_mail1\n",
"--boundary_mail1",
"Content-Type: multipart/alternative; boundary=boundary_mail2\n",
"--boundary_mail2",
"Content-Type: text/html; charset=UTF-8",
"Content-Transfer-Encoding: quoted-printable\n",
`${body}\n`,
"--boundary_mail2--",
"--boundary_mail1",
`Content-Type: ${mimeType}`,
`Content-Disposition: attachment; filename = "${name}"`,
"Content-Transfer-Encoding: base64\n",
fileContent,
"--boundary_mail1--",
].join("\n");
return Buffer.from(message)
.toString("base64")
.replace(/\+/g, "-")
.replace(///g, "_")
.replace(/=+$/, "");
}
const gmail = google.gmail({ version: "v1", auth }); // Please set your client
const drive = google.drive({ version: "v3", auth }); // Please set your client
// Please set your values.
const fileId = "###";
const user = { email: "###" };
const to = "###";
const subject = "sample subject";
const htmlBody = "sample HTML body.";
const res = await gmail.users.drafts.create({
userId: user.email,
requestBody: { message: { raw: await createRawMessage(to, subject, htmlBody, drive, fileId) } },
});
console.info(res.data);
fileId
не является файлом Google Docs (Документы, Таблицы, Слайды и т. д.). Пожалуйста, будьте осторожны с этим.@Deep Trikannad Спасибо за ответ. Из вашего ответа я добавил еще один пример сценария. Пожалуйста, подтвердите это.
Спасибо @Tanaike за быстрый ответ. Я знаю, что могу загрузить его и закодировать, чтобы прикрепить к электронному письму, но я пытался избежать этого шага и вместо этого заставил API Gmail извлекать его напрямую с Google Диска через FileId.
@Deep Trikannad Спасибо за ответ. По поводу but I was trying to avoid that step and instead have the Gmail API pull it directly from Google Drive via the FileId.
, итак, я предложил 1-й подход. Но, скажете вы but I'd like to actually add the attachment
. И, судя по I have this working in a Google Apps Script, but now trying to migrate this functionality to NodeJS.
и добавленному вами скрипту Google Apps, я подумал, что вы хотите преобразовать отображаемый скрипт Google Apps в Node.js. Итак, я предложил второй подход. Я думаю, что мой второй сценарий даст тот же результат, что и ваш.
Спасибо @Tanaike. Я также обратился по этому поводу в службу поддержки Google, и они сказали то же самое, что вы предложили. Таким образом, я принял ваш ответ. Еще раз спасибо!
@Deep Trikannad Спасибо за ответ. Я понимаю ваш ответ. И тебе спасибо.
Спасибо, что ответили мне по этому поводу. Я думал просто поместить
webViewLink
в тело сообщения, но мне хотелось бы добавить вложение. Я обновил исходное сообщение, добавив пример кода, который работает в скрипте Google Apps.