node.js - NodeMailer - 使用 Google 服务帐户发送邮件失败,因为 "Username and Password not accepted"

标签 node.js email google-oauth google-apps nodemailer

我正在创建一个 Twitter 机器人,我正在实现一种方法,如果出现错误,它会向我发送电子邮件。由于我已经在使用 google API 访问 Google Drive(这里没有问题),我决定使用服务帐户发送电子邮件(Google 控制台说可以那样使用)

到目前为止,我想出的发送电子邮件的方法是:

var config = require('./config/mail');
var google = require('./config/google');
var nodemailer = require('nodemailer');

var send = function (args) {
  let transporter = nodemailer.createTransport({
    'service': 'gmail',
    'auth': {
        'type': 'OAuth2',
        'user': google.client_email,
        'serviceClient': google.client_id,
        'privateKey': google.private_key
    }
  });
  transporter.on('token', token => console.log(token));

  let message = {
    'from': `"${config.serverFromName}" <${config.serverFromMail}>`,
    'to': args.to,
    'subject': args.subject,
    'text': args.text,
    'html': `<p>${args.text}</p>`
  };

  transporter.sendMail(message, (err, info) => {
    if (err) {
      console.log('Mail couldn\'t be sent because: ' + err);
    } else {
      console.log('Mail sent');
    }
  });
};

config/google 文件包含 Google 在您创建服务帐户时为您生成的数据。 config.serverFromNameconfig.serverFromMail 是发件人的姓名和电子邮件(与服务帐户 ID 不同)。 args 包含 recient 电子邮件和内容

当我测试发送方法时,我在控制台中收到以下消息:

Mail couldn't be sent because: Error: Invalid login: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8  https://support.google.com/mail/?p=BadCredentials z123sm543690vkd.10 - gsmtp

我知道 token 已正确创建,因为我创建的监听器正在打印它:

{ user: 'name@project.iam.gserviceaccount.com',
  accessToken: 'ya29.ElmIBLxzfU_kkuZeyISeuRBeljmAe7HNTlwuG4K12ysUNo46s-eJ8NkMYHQqD_JrqTlH3yheNc2Aopu9B5vw-ivEqvPR4sTDpWBOg3xUU_4XiJEBLno8FHsg',
  expires: 1500151434603 }

在网上搜索了一下,发现可能是OAuth scope的问题。但是,所有谈论它的信息都指的是使用客户端 ID,而不是服务帐户。我也没有在 Google 开发者控制台中找到该选项。

对我做错了什么有什么想法吗?

最佳答案

底线:Google 描述服务帐户的具体方式与 nodemailer 不兼容。但是有办法!

我刚刚在同一个问题上花费了无数个小时!我得出的结论是,Google 的管理控制台已间接删除了一半此功能。第一次使用服务帐户时,控制台不提供授权(用户接受同意屏幕)所需范围的方法。

首先,跟随Node.JS Quickstart Google Drive API 授权范围和接收刷新 token 的说明。

  1. 转到 console.developers.google.com ,构建OAuth2.0 Client Id,下载client_secret.json文件。

  2. 创建一个单独的临时模块文件夹并使用 NPM 下载 google api 模块

    npm 安装 googleapis

    npm 安装 google-auth-library

  3. 创建一个 quickstart.js 文件

  4. 将您的 client_secret.json 文件放在 quickstart.js 旁边

  5. quickstart.js 中的第 7 行是一个数组,用于定义您打算允许应用程序访问的范围。根据需要修改它。强烈建议只为预期的内容提供访问权限。参见 Gmail API Scopes .

  6. 运行 node quickstart.js

  7. 在浏览器中打开 URL,进行身份验证,然后将代码从浏览器复制回终端窗口。这将下载一个 nodejs-gmail-quickstart.json 文件,该文件的位置将在 stdout 中提供。
    这是您无法为服务帐户完成的部分。此操作将 SCOPES 数组中提供的范围授权给下载的 access_token 和刷新 token 。

注意:access_token 的有效期为 1 小时。 refresh_token 是不朽的。

现在您拥有授权的 refresh_token! 接下来是在 Nodemailer 中使用 3LO 设置您的身份验证对象.我会更多地关注底部示例,因为并非所有值都是必需的。我的授权看起来像这样:

const mailbot = nodemailer.createTransport({
      host: 'smtp.gmail.com',
      port: 587,              // TLS (google requires this port for TLS)
      secure: false,          // Not SSL
      requireTLS: true,       // Uses STARTTLS command (nodemailer-ism)
      auth: {
          // **HIGHLY RECOMMEND** ALL values be
          //  read in from a file not placed directly in code.  
          // Make sure that file is locked down to only the server daemon
          type : 'OAuth2',
          user : config.client_email,
          scope : "https://www.googleapis.com/auth/gmail.send",
          clientId : config.client_id,
          clientSecret: secret,
          refreshToken: activeToken.refresh_token

          // AT RUNTIME, it looks like this:
          //type : 'OAuth2',
          //user : 'user@gmail.com',   // actual user being impersonated
          //scope : "", //Optional, but recommend to define for the action intended
          //clientId : '888888888998-9xx9x99xx9x99xx9xxxx9xx9xx9x88x8xxx.apps.googleusercontent.com',
          //clientSecret: 'XxxxxXXxX0xxxxxxxx0XXxX0',
          //refreshToken: '1/XXxXxsss-xxxXXXXXxXxx0XXXxxXXx0x00xxx'              
      }
 });

提示:Gmail 将重写使用授权用户帐户(假冒用户)发送的任何电子邮件的“发件人”字段。如果您想稍微自定义一下,请使用语法 { FROM: '"Display NAME" <user email>' }它不会覆盖您的显示名称选择,因为电子邮件匹配。

注意:nodemailer 将向 https://accounts.google.com/o/oauth2/token 发出 token 请求使用刷新 token 自动获取 access_token。

不幸的是,nodemailer 缺少将接收到的 token 直接保存到文件中的功能,而是仅使用 this.emit()。如果服务器保持事件状态,这将不是问题,但由于我的服务器只是突然爆发,它总是会导致延迟,因为每次都会请求新的 access_token。

[SECURITY] 希望这对您有用!松开 2LO 服务帐户的私钥加密是令人失望的,但至少这种客户端 ID 方式很难被欺骗。我担心安全性,但阅读更多我对这个实现没问题。参见 Google Identity Platform (Nodemailer 使用 HTTP/REST 细节)并给定

[1] Google's OAuth 2.0 endpoint is at https://accounts.google.com/o/oauth2/v2/auth. This endpoint is accessible only over HTTPS. Plain HTTP connections are refused.

[5] After the web server receives the authorization code, it can exchange the authorization code for an access token.

您最初使用 TLS 连接以获得授权代码,然后将其与您的客户端 ID 数据和一个 refresh_token 相匹配(您必须经历我们上面所做的麻烦),然后您可以收到一个 access_token 以实际与 Google API 交互.

只要您通过保持 OAuth2.0 客户端 ID(高度随机的用户名)、 secret 和刷新 token 尽可能独立、安全和隐藏来提高您的安全状况,您应该能够睡个好觉。 祝你好运!

关于node.js - NodeMailer - 使用 Google 服务帐户发送邮件失败,因为 "Username and Password not accepted",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45122313/

相关文章:

node.js - 全新安装 Node 模块后 npm install 抛出错误

javascript - 如何在 Node 上处理来自phonegap的req?

Python smtplib sendmail() 不适用于主题/正文

regex - Outlook 2010 中的未送达报告和 VBA 脚本

authentication - YouTube 直播 API 请求与 Api key

node.js - Google API NodeJS 库 OAuth2 请求

angularjs - cookie 未设置跨域 - AngularJS 和 NodeJS/Express

javascript - 无法从 React.js 将图像发布到我的 API 路由

android - 移动端如何检测邮件客户端: desktop or mobile,和平台?

android - 适用于 Android 的 Google 登录 : Cannot resolve RC_SIGN_IN