使用 nodemailer 在 Node.js 中发送电子邮件无效。

49

我已经设置了一个基本的NodeJS服务器(使用nodemailer模块)在本地(http://localhost:8080),只是为了测试服务器是否能够真正发送电子邮件。

如果我正确理解SMTP选项(如果我理解有误,请纠正我),我可以直接从我的服务器尝试向某人的电子邮件帐户发送电子邮件,或者我可以通过实际的电子邮件帐户(在这种情况下是我的个人Gmail帐户)使用Node.js发送电子邮件,即使用SMTP。这个选项需要我通过NodeJS远程登录到该帐户。

因此,在下面的服务器中,我实际上正在尝试使用NodeJs从我的个人电子邮件帐户向我的个人电子邮件帐户发送电子邮件。

以下是我的简单服务器:

var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport("SMTP", {
    service: 'Gmail',
    auth: {
        user: '*my personal Gmail address*',
        pass: '*my personal Gmail password*'
    }
});

var http = require('http');
var httpServer = http.createServer(function (request, response)
{
    transporter.sendMail({
       from: '*my personal Gmail address*',
       to: '*my personal Gmail address*',
       subject: 'hello world!',
       text: 'hello world!'
    });
}).listen(8080);

但是它没有起作用。 我收到了一封谷歌电子邮件,上面写着:

Google帐户:登录尝试被阻止 如果这是您本人的操作 您可以切换到由谷歌制作的应用程序(例如Gmail)以访问您的帐户(推荐),或者在https://www.google.com/settings/security/lesssecureapps更改您的设置, 使您的帐户不再受现代安全标准的保护。

我在nodemailer GitHub页面上找不到以上问题的解决方案。 有人有解决方案/建议吗?

谢谢!:-)

12个回答

87
答案在Google的邮件中。 对于问题的第二部分,并回应:

我只是按照nodemailer Github页面上的步骤进行操作,所以我的代码中没有错误。

我会参考nodemailer Github页面和以下代码片段:
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
    user: 'gmail.user@gmail.com',
    pass: 'userpass'
}
});

它与您的代码略有不同,因为您使用了nodemailer.createTransport("SMTP"。删除SMTP参数即可使其正常工作(已测试)。另外,为什么要将其封装在http服务器中?以下代码可以正常工作:

var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
        user: 'xxx',
        pass: 'xxx'
    }
});

console.log('created');
transporter.sendMail({
from: 'xxx@gmail.com',
  to: 'xxx@gmail.com',
  subject: 'hello world!',
  text: 'hello world!'
});

我想避免这种情况,因为我认为这可能会使我的账户更加容易受到攻击。我认为我可以通过一些可能被忽视的nodemailer设置来绕过这个问题。也许是设置一些额外的认证属性。不过还是谢谢! - Kawd
1
现在已经启用了,我不再收到来自谷歌的通知,但是我也没有收到电子邮件,所以恐怕仍然无法正常工作。 - Kawd
1
尝试使用不同的“发件人”和“收件人”地址,我之前在使用Gmail时遇到过类似的问题,除了自己以外的任何收件人都可以正常工作。 - xShirase
我建议这只是一个调试程序,以查看问题是来自您的代码还是来自Gmail。 - xShirase
我只是简单地按照nodemailer的github页面上的步骤进行操作,所以很遗憾我的代码中没有错误。但我会继续寻找答案,谢谢! - Kawd
显示剩余10条评论

32

已过时:JSON文件的输出中不再包含refreshToken和accessToken

如果你想要使用OAuth2/不想使应用程序“更不安全”,可以通过以下方式实现:

  1. Google API控制台搜索“Gmail API”并点击“启用”
  2. 按照https://developers.google.com/gmail/api/quickstart/nodejs上的步骤进行操作。在quickstart.js文件中,将SCOPES变量从['https://www.googleapis.com/auth/gmail.readonly']更改为['https://mail.google.com/'],如https://nodemailer.com/smtp/oauth2/中的故障排除建议所示
  3. 按照步骤(2)执行后,生成的JSON文件将包含Nodemailer OAuth2示例中所需的acessTokenrefreshTokenexpires属性

这样你就可以像以下方式一样使用OAuth2身份验证了:

let transporter = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
        type: 'OAuth2',
        user: 'user@example.com',
        clientId: '000000000000-xxx0.apps.googleusercontent.com',
        clientSecret: 'XxxxxXXxX0xxxxxxxx0XXxX0',
        refreshToken: '1/XXxXxsss-xxxXXXXXxXxx0XXXxxXXx0x00xxx',
        accessToken: 'ya29.Xx_XX0xxxxx-xX0X0XxXXxXxXXXxX0x',
        expires: 1484314697598
    }
});

不要以明文形式存储您的Gmail密码,并降低帐户的安全性。


2
不再有效,accessToken和refreshToken在该文件中不再存在。 - CaptRisky
2
为了使其正常工作,我结合了这个回答的传输定义(没有指定accessToken和expires),以及这篇文章,使用Google的OAuth Playground来获取刷新令牌:https://medium.com/@pandeysoni/nodemailer-service-in-node-js-using-smtp-and-xoauth2-7c638a39a37e - apricity
我的gmail-nodejs-quickstart.json文件中没有SCOPES变量。 - Kirby
2
@CaptRisky 关于您的评论“accessToken和refreshToken不再存在于该文件中”的说法是不准确的。我按照说明进行操作,确实生成了一个包含所有值的token.json文件:access_token、refresh_token、scope、token_type和expiry_date。 - user2101068
1
@ironicaldiction 希望您能给我一些建议。我按照您上面列出的所有步骤进行了操作,但每次访问令牌过期时,我的nodejs应用程序都无法发送电子邮件。具体来说,在Postman中我会收到以下消息响应:{"code": "EAUTH", "command": "AUTH XOAUTH2"}。您有什么想法吗? - user2101068
显示剩余2条评论

18
我已经将我的域名设置为:smtp.gmail.com,它可以使用。我正在使用VPS Vultr。
代码:
const nodemailer = require('nodemailer');
const ejs = require('ejs');
const fs = require('fs');

let transporter = nodemailer.createTransport({
    host: 'smtp.gmail.com',
    port: 465,
    secure: true,
    auth: {
        user: 'xxx@gmail.com',
        pass: 'xxx'
    }
});

let mailOptions = {
    from: '"xxx" <xxx@gmail.com>',
    to: 'yyy@gmail.com',
    subject: 'Teste Templete ✔',
    html: ejs.render( fs.readFileSync('e-mail.ejs', 'utf-8') , {mensagem: 'olá, funciona'})
};

transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
        return console.log(error);
    }
    console.log('Message %s sent: %s', info.messageId, info.response);
});

我的ejs模板(email.ejs):

<html>
    <body>
        <span>Esse é um templete teste</span>
        <p> gerando com o EJS - <%=mensagem%> </p>
    </body>
</html>

请确保:

  • 安装 ejs:npm install ejs --save
  • 安装 nodemailer:npm install nodemailer --save
  • ping smtp.gmail.com 可以正常工作:ping smtp.gmail.com
  • 将 xxx@gmail.com 更改为您的 Gmail 邮箱
  • 将 yyy@gmail.com 更改为您要发送电子邮件的邮箱
  • 启用较不安全的应用程序
  • 暂时禁用验证码

祝您拥有愉快的一天;)


使用 port: 465 有什么区别吗?另外,如果你有 host:,那是否就不需要添加 service: 'Gmail' 了呢? - Cezar Cobuz
SMTP默认端口是:25、465和587,因此port: 465非常重要以使其明确。根据nodemailer文档,在createTransport中不提供此service属性,只有host - Mathias Gheno Azzolini

10

虽然以上答案有效,但我想指出您可以通过以下两个步骤降低 Gmail 的安全性。

步骤1

Google 账户:登录尝试被阻止 如果这是您的操作,您可以切换到由 Google 制作的应用程序,如 Gmail 来访问您的账户(推荐),或在https://www.google.com/settings/security/lesssecureapps更改设置,以便您的账户不再受现代安全标准的保护。

步骤2

除了启用“允许非安全应用程序”外,您还可能需要导航至https://accounts.google.com/DisplayUnlockCaptcha并单击“继续”。


2
那就是缺失的一步:https://accounts.google.com/DisplayUnlockCaptcha 谢谢!! - wilmerlpr

7

您只需要使用App密码来进行谷歌验证,然后将代码中的谷歌密码替换掉。

请在此处获取App密码。

示例代码:

const nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
    service: "Gmail",
    auth: {
      user: 'example@gmail.com',
      pass: 'app password here'
    }
  });
transporter.sendMail(option, function(error, info){
    if (error) {
      console.log(error);
    } else {
      console.log('Email sent: ' + info.response);
    }
});

screenshot


2
不知道为什么,但这在本地主机上可以运行,而在我的暂存环境中却不能。 - Harpreet Singh
2
@HarpreetSingh 你好,这个程序能在Azure云环境中运行吗?对我来说,在本地是可以运行的,但在云端就不行了。如果你能更新一下这个问题,那对我来说会非常有用。 - sasi
@sasi,它某种程度上起作用了,但我不记得具体是怎么做的了。抱歉。 - Harpreet Singh

4

安装smtp模块作为依赖项:

npm install smtp

var nodemailer = require('nodemailer');

var transporter = nodemailer.createTransport({
  service: 'gmail',
  type: "SMTP",
  host: "smtp.gmail.com",
  secure: true,
  auth: {
    user: 'writeYourGmailId@gmail.com',
    pass: 'YourGmailPassword'
  }
});

var mailOptions = {
  from: 'xyz.khan704@gmail.com',
  to: 'azran.khan704@gmail.com',
  subject: 'Sending Email to test Node.js nodemailer',
  text: 'That was easy to test!'
};

transporter.sendMail(mailOptions, function(error, info){
  if (error) {
    console.log(error);
  } else {
    console.log('Email sent');
  }
});

请前往https://myaccount.google.com/lesssecureapps,并将其更改为开启。因为某些应用和设备使用了不太安全的登录技术,这会增加您的帐户风险。您可以关闭这些应用的访问权限(我们建议这样做),或打开访问权限以便在冒一定风险的情况下使用它们。


4

为了调试目的,实现一个回调函数非常方便(在nodemailer的github页面上它们从来没有这样做),它显示错误消息(如果有)。

transporter.sendMail({
    from: from,
    to: to,
    subject: subject,
    html: text
}, function(err){
    if(err)
        console.log(err);
})

它帮助我解决了我的问题... 原来新版本不能正常工作:

"看起来nodemailer 1.0有重大变化,因此必须使用0.7:http://www.nodemailer.com/

nodemailer发布的消息截至2015年12月17日:

不要将Nodemailer从0.7或更低版本升级到1.0,因为存在重大变化。只要您愿意,您可以继续使用0.7分支。请查看0.7的文档 here。"

我在这里找到了答案here


2
“您不应再使用Gmail密码!”最近,谷歌提供了一种在第三方应用程序或API中使用的新方法。 您需要使用“应用程序密码”而不是Gmail密码。 但是,要创建它,您需要在Google帐户中启用两步验证模式:您可以在此处找到步骤:https://support.google.com/mail/answer/185833?hl=en

1

尝试这段代码,它对我有效。

var http = require('http');
var nodemailer = require('nodemailer');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});

  var fromEmail = 'akarthi@xyz.com';
  var toEmail = 'akarthi@xyz.com';

  var transporter = nodemailer.createTransport({
    host: 'domain',
    port: 587,
    secure: false, // use SSL
    debug: true,
      auth: {
        user: 'fromEmail@xyz.com',
        pass: 'userpassword'
      }
  });
   transporter.sendMail({
      from: fromEmail,
      to: toEmail,
      subject: 'Regarding forget password request',
      text: 'This is forget password response from your app',
      html: '<p>Your password is <b>sample</b></p>'
  }, function(error, response){
      if(error){
          console.log('Failed in sending mail');
          console.dir({success: false, existing: false, sendError: true});
          console.dir(error);
          res.end('Failed in sending mail');
      }else{
          console.log('Successful in sending email');
          console.dir({success: true, existing: false, sendError: false});
          console.dir(response);
          res.end('Successful in sending email');
      }
  });
}).listen(8000);
console.log('Server listening on port 8000');

响应:

Successful in sending email
{ success: true, existing: false, sendError: false }
{ accepted: [ 'akarthi@xyz.com' ],
  rejected: [],
  response: '250 2.0.0 uAMACW39058154 Message accepted for delivery',
  envelope: 
   { from: 'akarthi@xyz.com',
     to: [ 'akarthi@xyz.com' ] },
  messageId: '1479809555147-33de4987-29d605fa-6ee150f1@xyz.com' }

0

enter image description here

补充xShirase的答案,提供启用截图。同时在安全性方面确认之前的尝试是由您完成的。

xShirase值得所有赞。我只是展示截图。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接