我正在创建一个Twitter机器人,我正在实现一种方法,如果出现错误,会向我发送电子邮件。由于我已经使用谷歌API访问谷歌硬盘(这里没有问题),我决定使用服务帐户发送电子邮件(谷歌控制台说它可以这样使用)
我到目前为止发送电子邮件的方法是:
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.serverFromName
和config.serverFromMail
是发件人的姓名和电子邮件(与服务帐户ID不同)。 args
包含食谱电子邮件和内容
当我测试send方法时,我在控制台中收到以下消息:
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
我知道令牌正在被正确创建,因为我创建的监听器正在打印它:
{ user: '[email protected]',
accessToken: 'ya29.ElmIBLxzfU_kkuZeyISeuRBeljmAe7HNTlwuG4K12ysUNo46s-eJ8NkMYHQqD_JrqTlH3yheNc2Aopu9B5vw-ivEqvPR4sTDpWBOg3xUU_4XiJEBLno8FHsg',
expires: 1500151434603 }
在互联网上搜索我发现它可能是OAuth范围的问题。但是,所有涉及它的信息都是指使用客户端ID,而不是服务帐户。我也没有在Google开发者控制台中找到该选项。
我做错了什么想法?
结论:Google描述服务帐户的具体方式与nodemailer不兼容。但有一种方法!
我在同样的问题上花了无数个小时!我得出结论,谷歌的管理控制台间接地删除了一半这个功能。控制台不提供使用服务帐户第一次授权(用户接受同意屏幕)所需范围的方法。
首先,按照Google Drive API的Node.JS Quickstart说明授权范围并接收刷新令牌。
node quickstart.js
注意:access_token的使用寿命为1小时。 refresh_token是不朽的。
现在你有一个授权的refresh_token!接下来是在Nodemailer中使用3LO设置auth对象。我会更多地看底部示例,因为并非所有值都是必需的。我的身份证明如下:
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 : '[email protected]', // 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字段。如果您想稍微自定义,请使用语法{ FROM: '"Display NAME" <user email>' }
,因为电子邮件匹配,它不会覆盖您的显示名称选项。
注意:nodemailer将使用刷新令牌向https://accounts.google.com/o/oauth2/token发出令牌请求,以自动获取access_token。
遗憾的是,nodemailer缺乏将接收到的令牌直接保存到文件中的功能,而只是使用this.emit()。如果服务器保持活动状态,则不会出现问题,但由于我的服务器只是爆破,因此每次都会请求新的access_token,因此总会产生延迟。
[安全]希望这适合你!松开私钥加密服务帐户2LO会带来令人失望,但至少这种客户端ID方式很难欺骗。我担心安全问题,但阅读更多我对这个实现很满意。请参阅Google Identity Platform(Nodemailer使用HTTP / REST详细信息)并给出
[1] Google的OAuth 2.0端点位于https://accounts.google.com/o/oauth2/v2/auth。此端点只能通过HTTPS访问。纯HTTP连接被拒绝。
[5] Web服务器收到授权码后,可以交换访问令牌的授权码。
您使用TLS最初连接授权代码,然后将其与您的客户端ID数据匹配,以及refresh_token(您必须经历我们上面所做的麻烦)然后您可以收到access_token以实际与Google API交互。
只要您将OAuth2.0客户端ID(高度随机的用户名),密码和刷新令牌尽可能地保持独立,安全和隐藏,就可以提高安全性,您应该能够安然入睡。祝好运!