用于在Node.js中发送邮件的Gmail API

Ser*_*gio 14 node.js google-api-nodejs-client gmail-api

免责声明:

  • 我已经关注了Google自己的Node.js快速入门指南,并成功连接并使用了该 gmail.users.labels.list()功能.
  • 我在这里检查了问题/答案,就像这个(不是使用我询问的Node.js API),或者这个(类似于这个),这显然是我遇到的同样的问题,但解决方案没有工作.

我的问题:

使用Google的Node.js API时,尝试发送电子邮件时出错.错误是:

{
    "code": 403,
    "errors": [{
        "domain": "global",
        "reason": "insufficientPermissions",
        "message": "Insufficient Permission"
    }]
}
Run Code Online (Sandbox Code Playgroud)

我的设置:

fs.readFile(secretlocation, function processClientSecrets(err, content) {
    if (err) {
        console.log('Error loading client secret file: ' + err);
        return;
    }
    authorize(JSON.parse(content), sendMessage);
});

function sendMessage(auth) {
    var raw = makeBody('myrealmail@gmail.com', 'myrealmail@gmail.com', 'subject', 'message test');
    gmail.users.messages.send({
        auth: auth,
        userId: 'me',
        message: {
            raw: raw
        }
    }, function(err, response) {
        res.send(err || response)
    });
}
Run Code Online (Sandbox Code Playgroud)

该功能processClientSecrets来自我上面提到的Google指南.它读取我的.json文件,包含我的access_tokenrefresh_token.该makeBody函数用于制作编码的正文消息.

在配置变量我也有:

var SCOPES = [
    'https://mail.google.com/',
    'https://www.googleapis.com/auth/gmail.modify',
    'https://www.googleapis.com/auth/gmail.compose',
    'https://www.googleapis.com/auth/gmail.send'
];
Run Code Online (Sandbox Code Playgroud)

为什么它应该工作:

  • 授权过程适用于该gmail.users.labels.list()方法.
  • 如果我在Google的测试页面测试它,我正在测试的消息正文.

我的问题:

我的设置错了吗?API有变化吗?我错过了什么?

Ser*_*gio 20

好的,所以我发现了问题.

问题#1 在遵循Node.js快速入门指南时,该教程中的示例有

var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];
Run Code Online (Sandbox Code Playgroud)

当我得到.json它看起来像:

{
    "access_token": "xxx_a_long_secret_string_i_hided_xxx",
    "token_type": "Bearer",
    "refresh_token": "xxx_a_token_i_hided_xxx",
    "expiry_date": 1451721044161
}
Run Code Online (Sandbox Code Playgroud)

生成的令牌考虑auth/gmail.readonly教程代码中的范围.

所以我删除了第一个.json,添加了我的最终范围数组中的范围(我在问题中发布)并再次运行教程设置,接收新标记.

问题#2

在传递给我发送的API的对象中:

{
    auth: auth,
    userId: 'me',
    message: {
        raw: raw
    }
}
Run Code Online (Sandbox Code Playgroud)

但这是错误的,message应该调用密钥resource.


最终设置:

这是我在教程代码中添加的内容:

function makeBody(to, from, subject, message) {
    var str = ["Content-Type: text/plain; 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
    ].join('');

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

function sendMessage(auth) {
    var raw = makeBody('myrealemail@gmail.com', 'myrealemail@gmail.com', 'test subject', 'test message');
    gmail.users.messages.send({
        auth: auth,
        userId: 'me',
        resource: {
            raw: raw
        }
    }, function(err, response) {
        res.send(err || response)
    });
}
Run Code Online (Sandbox Code Playgroud)

并呼吁一切:

fs.readFile(secretlocation, function processClientSecrets(err, content) {
    if (err) {
        console.log('Error loading client secret file: ' + err);
        return;
    }
    // Authorize a client with the loaded credentials, then call the
    // Gmail API.
    authorize(JSON.parse(content), sendMessage);
});
Run Code Online (Sandbox Code Playgroud)

  • @ArjunKava 只需设置`Content-Type: text/html;` 而不是`Content-Type: text/plain;`。 (4认同)
  • 请,您能解释一下为什么需要对base64原始消息进行一些替换吗?谢谢 (2认同)
  • 我也想知道为什么他们替换了base64内容。另外,在哪里可以找到有关原始内容的文档,这些文档位于资源属性内。 (2认同)

Vin*_*ris 8

因此,对于任何查看此内容并尝试从其 API 发送测试电子邮件但无法完成此工作的人,您需要执行以下操作:

第 1 步:更换

var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];
Run Code Online (Sandbox Code Playgroud)

有了这个:

var SCOPES = [
    'https://mail.google.com/',
    'https://www.googleapis.com/auth/gmail.modify',
    'https://www.googleapis.com/auth/gmail.compose',
    'https://www.googleapis.com/auth/gmail.send'
];
Run Code Online (Sandbox Code Playgroud)

步骤 2:在 google 示例代码末尾添加以下内容:

function makeBody(to, from, subject, message) {
    var str = ["Content-Type: text/plain; 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
    ].join('');

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

function sendMessage(auth) {
    var raw = makeBody('Receiverofyouremail@mail.com', 'whereyouaresendingstufffrom@gmail.com', 'This is your subject', 'I got this working finally!!!');
    const gmail = google.gmail({version: 'v1', auth});
    gmail.users.messages.send({
        auth: auth,
        userId: 'me',
        resource: {
            raw: raw
        }
    
    }, function(err, response) {
        return(err || response)
    });
}

fs.readFile('credentials.json', function processClientSecrets(err, content) {
    if (err) {
        console.log('Error loading client secret file: ' + err);
        return;
    }
    // Authorize a client with the loaded credentials, then call the
    // Gmail API.
    authorize(JSON.parse(content), sendMessage);
});
Run Code Online (Sandbox Code Playgroud)

步骤3(可选)

删除这一行:

authorize(JSON.parse(content), listLabels);
Run Code Online (Sandbox Code Playgroud)

还有这些:

/**
 * Lists the labels in the user's account.
 *
 * @param {google.auth.OAuth2} auth An authorized OAuth2 client.
 */
 function listLabels(auth) {
   const gmail = google.gmail({version: 'v1', auth});
   gmail.users.labels.list({
     userId: 'me',
   }, (err, res) => {
     if (err) return console.log('The API returned an error: ' + err);
     const labels = res.data.labels;
     if (labels.length) {
       console.log('Labels:');
       labels.forEach((label) => {
         console.log(`- ${label.name}`);
       });
     } else {
       console.log('No labels found.');
     }
   });
 }
Run Code Online (Sandbox Code Playgroud)

(所以你不会在控制台中获得随机标签)