如何在 Node.js 中使用 Gmail API 发送带有附件的电子邮件?

2024-03-15

我是 Node.js 新手,我正在尝试使用 Gmail API 创建邮箱,除了上传电子邮件中的附件之外,一切正常。我找到了 Java、Python 和 C# 的示例,但我找不到任何有关它的 Node 文档。 任何提示将非常感激。

这是我的代码:

function makeBody(to, from, subject, message) {
    var str = ["Content-Type: multipart/mixed; charset=\"UTF-8\"\n",
        "MIME-Version: 1.0\n",
        "Content-Transfer-Encoding: 7bit\n",
        "to: ", to, "\n",
        "from: ", from, "\n",
        "subject: ", subject, "\n\n",
        message,
        file
    ].join('');

    var encodedMail = new Buffer(str).toString("base64").replace(/\+/g, '-').replace(/\//g, '_');

    return encodedMail;
}

function sendMessage(auth) {
    var raw = makeBody(tap, 'me', response.subject, response.content, response.files);
    gmail.users.messages.send({
        auth: auth,
        userId: 'me',
        resource: {
            raw: raw
        }
    }, function (err, response) {
        if (err) {
            console.log('Error  ' + err);
            return;
        }

        if (response) {
            res.sendFile(__dirname + '/boite.html')
        }
    });
}

这可能有点晚了,无论如何,我会花时间以防后来有人想要替代方案。

Moxched 方法的主要问题是,他可能需要仔细查看 MIME 规范(这对我来说是一个很大的痛苦),以更好地理解发送附件所需的一些内容。

从我的立场来看,为了能够使用 gmail API 发送附件和许多其他内容,您必须根据 MIME 规范构建所有请求,为此您需要了解 MIME 中的内容(包括边界)如何工作。

Joris 方法有效,但最终没有使用 NodeJS 库来发送电子邮件。他无法使用来自的答案的原因gmail-api-create-message-body与 gmail API 一起打包是因为由于某种原因该库在其 MIME 消息的顶部生成以下内容:

'Content-Type: multipart/related; boundary="foo_bar_baz"',
`In-Reply-To: [email protected] /cdn-cgi/l/email-protection`,
`References: `,
`From: [email protected] /cdn-cgi/l/email-protection`,
`Subject: SUBJECT`,
`MIME-Version: 1.0`,
'',
`--foo_bar_baz`,
`Content-Type: application/json; charset="UTF-8"`,
'',
`{`,
`}`,
'',
`--foo_bar_baz`,
`Content-Type: message/rfc822`,
'',
...

由于某种原因,gmailAPI 不喜欢这样......

我的建议是更好地理解 MIME 规范,一个非常简单的方法是使用一些旧的逆向工程,为此我建议查看来自gmail-api-create-message-body and mail-composer来自节点邮件程序。

Using nodemailer/lib/mail-composer您将能够根据 MIME 规范轻松生成必要的 MIME 消息,它包括附件支持和所有其他内容。生成的 MIME 消息与 Gmail API 兼容。我留下了一个基于 NodeJS 文档示例的工作示例,该示例发送一封带有 2 个附件的电子邮件。

希望这可以帮助!

const fs = require('fs');
const path = require('path');
const readline = require('readline');
const {google} = require('googleapis');

const MailComposer = require('nodemailer/lib/mail-composer');

// If modifying these scopes, delete token.json.
const SCOPES = [
  'https://mail.google.com',
  'https://www.googleapis.com/auth/gmail.readonly'
];
const TOKEN_PATH = 'token.json';

// Load client secrets from a local file.
fs.readFile('credentials.json', (err, content) => {
  if (err) return console.log('Error loading client secret file:', err);
  // Authorize a client with credentials, then call the Gmail API.
  //authorize(JSON.parse(content), listLabels);

  authorize(JSON.parse(content), sendEmail);

});

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(credentials, callback) {
  const {client_secret, client_id, redirect_uris} = credentials.installed;
  const oAuth2Client = new google.auth.OAuth2(
    client_id, client_secret, redirect_uris[0]);

  // Check if we have previously stored a token.
  fs.readFile(TOKEN_PATH, (err, token) => {
    if (err) return getNewToken(oAuth2Client, callback);
    oAuth2Client.setCredentials(JSON.parse(token));
    callback(oAuth2Client);
  });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
function getNewToken(oAuth2Client, callback) {
  const authUrl = oAuth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: SCOPES,
  });
  console.log('Authorize this app by visiting this url:', authUrl);
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  rl.question('Enter the code from that page here: ', (code) => {
    rl.close();
    oAuth2Client.getToken(code, (err, token) => {
      if (err) return console.error('Error retrieving access token', err);
      oAuth2Client.setCredentials(token);
      // Store the token to disk for later program executions
      fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
        if (err) return console.error(err);
        console.log('Token stored to', TOKEN_PATH);
      });
      callback(oAuth2Client);
    });
  });
}

function sendEmail(auth) {

  // ----------nodemailer test----------------------------------------------------

  let mail = new MailComposer(
    {
      to: "[email protected] /cdn-cgi/l/email-protection",
      text: "I hope this works",
      html: " <strong> I hope this works </strong>",
      subject: "Test email gmail-nodemailer-composer",
      textEncoding: "base64",
      attachments: [
        {   // encoded string as an attachment
          filename: 'text1.txt',
          content: 'aGVsbG8gd29ybGQh',
          encoding: 'base64'
        },
        {   // encoded string as an attachment
          filename: 'text2.txt',
          content: 'aGVsbG8gd29ybGQh',
          encoding: 'base64'
        },
      ]
    });

  mail.compile().build( (error, msg) => {
    if (error) return console.log('Error compiling email ' + error);

    const encodedMessage = Buffer.from(msg)
      .toString('base64')
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');

    const gmail = google.gmail({version: 'v1', auth});
    gmail.users.messages.send({
      userId: 'me',
      resource: {
        raw: encodedMessage,
      }
    }, (err, result) => {
      if (err) return console.log('NODEMAILER - The API returned an error: ' + err);

      console.log("NODEMAILER - Sending email reply from server:", result.data);
    });

  })

  // ----------nodemailer test----------------------------------------------------


}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Node.js 中使用 Gmail API 发送带有附件的电子邮件? 的相关文章

随机推荐

  • 用于更新 JTable 中给定单元格/列并增加焦点的侦听器类型

    我正在尝试使用预定义第一列的 JTable 用户仅将数据输入到第二列 数量 然后 我通过将 服务 列和 数量 列相乘来计算最终收入 并将其显示在第三列 收入 中 Service Quantity Income 40 00 X 40 00 3
  • Java:HashMap 大小是“质数”还是“2 的幂”?

    许多书籍和教程都说哈希表的大小必须是素数才能将键均匀分布在所有桶中 但是Java的HashMap始终使用 2 的幂的大小 难道不应该使用素数吗 作为哈希表大小 质数 或 2 的幂 哪个更好 使用 2 的幂可以有效地屏蔽哈希码的最高位 因此
  • Blend 2 sp1 中的 WPF 视觉状态管理器

    谁能向我解释如何让视觉状态管理器与 WPF 应用程序一起使用 它刚刚被添加到新的 wpftoolkit 中 我按照说明安装了它 但即使是示例也没有显示 VSM 在 silverlight 中它可以工作 但在 WPF 中不行 如果安装了最新的
  • Oracle 上个月的日期函数

    我有下面的查询 其中日期是硬编码的 我的目标是删除编码日期 查询运行时应提取上个月的数据 select count distinct switch id from email protected cdn cgi l email protec
  • a:active a href 不起作用

    我正在尝试在 a href 上应用 css 基本上我需要在单击 a href 时应用与悬停相同的样式以指示用户所在的页面 有任何想法吗 active意思是 被点击 或以其他方式激活 时 它并不意味着 链接到当前页面 CSS 与之最接近的是
  • 更改 UICollectionViewCell 中的标签位置

    我们有一个UICollectionView故事板上有一个原型单元 该细胞有一个UILabel label 其中 其定位没有自动布局 我们有条件地设置标签的框架 collectionView cellForItemAtIndexPath 像这
  • 根据 Beautifulsoup 中的内容排除标签

    我正在抓取类似于以下内容的 html 数据 div class target content p the content of the p p p the content of the p p p p div
  • G++ CAS (__sync_val_compare_and_swap) 问题需要解释

    这让我很头疼 我正在尝试实现一些 无锁 代码 并使用 CAS gcc sync val compare and swap 来完成繁重的工作 我的问题可以用下面的代码来显示 volatile bool lock void locktest v
  • 如何使用 vba 更新 powerpoint 2010 中嵌入的 Excel 链接

    我的问题是我已将图表粘贴到微软幻灯片软件 questions tagged powerpoint我正在尝试通过 Excel VBA 更新嵌入的链接 我尝试过下面的代码但失败了 code 1 AppPPT Presentations Open
  • jQuery/javascript 替换标签类型

    有没有一种简单的方法可以循环遍历所有 td 标签并将它们更改为 th ETC 我当前的方法是用 th 包裹它们 然后删除 td 但随后我会丢失其他属性等 jQuery replaceTagName 以下是一个 jQuery 插件 用于替换
  • Woocommerce 自定义产品列表分页

    我有这样的代码用于在 woocommerce 中获取和显示产品 args array post type gt product posts per page gt 30 loop new WP Query args if loop gt h
  • 421 4.3.0 临时系统问题。稍后重试 (10) [重复]

    这个问题在这里已经有答案了 我正在使用nodemailer npm 包和gmail 作为nodejs 中的服务 对于某些电子邮件 我收到以下错误 Data command failed 421 4 3 0 Temporary System
  • 只有一个(自定义)注释从一系列其他注释中轮换

    我的应用程序即将进入最后阶段 该阶段显示公交车的实时地图 所以 基本上 我有一个计时器 它定期从提供公交车实时位置的 xml 表中获取公交车的纬度和经度 我能够设置 xml 解析器 为公交车的移动设置动画并为公交车设置自定义 箭头 图像 然
  • Linq 中的 ISNULL 等效项

    我有一张带有一列的桌子IsActive现在我想获取具有给定状态的记录列表 但我想处理IsActive将 null 值视为 false 在 SQL 中我们使用 SELECT FROM dbo Table c WHERE ISNULL IsAc
  • 为什么 pip 需求文件包含“@​​file”而不是版本号?

    我使用 pip freeze gt requirements txt 创建了requirements txt 有些模块显示 file 而不是版本 它是什么意思以及为什么会显示 康达 4 8 3 这是requirements txt 的结果
  • 为什么对 C 枚举定义中的值使用按位移位运算符?

    Apple 有时会在其应用程序中使用按位移位运算符enum定义 例如 在CGDirectDisplay h文件是核心图形的一部分 enum kCGDisplayBeginConfigurationFlag 1 lt lt 0 kCGDisp
  • -[NSResponder swipeWithEvent:] 未调用

    我正在编写一个针对 OS X Lion 和 Snow Leopard 的应用程序 我有一个观点 我想响应滑动事件 我的理解是三指滑动会调用 NSResponder swipeWithEvent 如果该方法在我的自定义视图中实现 我已经看过了
  • 如何让 Doctrine 正确处理 ENUM?

    在一个应用程序中我有一个案例类表继承 https www doctrine project org projects doctrine orm en 2 6 reference inheritance mapping html class
  • 如何在 Unix 中从键盘设备捕获用户输入?

    我想从键盘设备捕获所有用户输入 一次读取一个字节 我编写了以下代码 但它不起作用 if fd open dev char O RDONLY 1 tty open dev tty O RDONLY tcsetattr 0 TCSANOW or
  • 如何在 Node.js 中使用 Gmail API 发送带有附件的电子邮件?

    我是 Node js 新手 我正在尝试使用 Gmail API 创建邮箱 除了上传电子邮件中的附件之外 一切正常 我找到了 Java Python 和 C 的示例 但我找不到任何有关它的 Node 文档 任何提示将非常感激 这是我的代码 f