用于在节点 js javascript 文件中发送用户消息的 gmail API

Posted

技术标签:

【中文标题】用于在节点 js javascript 文件中发送用户消息的 gmail API【英文标题】:gmail API for sending users messages in nodejs javascript failes 【发布时间】:2018-08-01 12:45:01 【问题描述】:

我的 nodejs 程序无法使用 Gmail api 发送消息。

Gmail API for sending mails in Node.js 的解决方案对我不起作用。

我用

对电子邮件进行编码
var google = require('googleapis');

// to and from = "some name <blaw.blaw.com"
function makeBody(to, from, subject, message) 
    var str = ["Content-Type: text/plain; charset=\"UTF-8\"\r\n",
        "MIME-Version: 1.0\r\n",
        "Content-Transfer-Encoding: 7bit\r\n",
        "to: ", to, "\r\n",
        "from: ", from, "\r\n",
        "subject: ", subject, "\r\n\r\n",
        message
    ].join('');

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

    return encodedMail;

然后转到 Google API 资源管理器 https://developers.google.com/apis-explorer/#p/ 输入 gmail.users.messages.send 和上面 make_body 生成的字符串。

一封电子邮件将被成功发送。所以我知道上面的编码是 好的。

当我的程序尝试使用以下发送时,它失败并出现错误

错误:“原始”RFC822 有效负载消息字符串或通过上传消息 /upload/* 需要网址

function sendMessage(auth) 
    var gmail = google.gmail('v1');
    var raw = makeBody('john g <asdfasdf@hotmail.com>', 'john g<asfasdgf@gmail.com>', 'test subject', 'test message #2');

    gmail.users.messages.send(
        auth: auth,
        userId: 'me',
        resource: 
            raw: raw
        

    , function(err, response) 
        console.log(err || response)
    );

身份验证令牌很好,因为我可以调用 gmail.users.labels.list 并且在使用 API 资源管理器时使用相同的授权。

Q1:有谁知道为什么上述方法不起作用?

Q2:Gmail API for sending mails in Node.js 没有解释为什么原始电子邮件消息被包装在资源字段中。我尝试了简单的原始方法,但没有帮助。

这失败了。

gmail.users.messages.send(
        auth: auth,
        userId: 'me',
        resource: 
            raw: raw
        

    , function(err, response) 
        console.log(err || response)
    );

也是如此

gmail.users.messages.send(
    auth: auth,
    userId: 'me',
    raw: raw

, function(err, response) 
    console.log(err || response)
);

GMAIL API for sending Email with attachment也是如此

gmail.users.messages.send(
    auth: auth,
    userId: 'me',
    data: raw

, function(err, response) 
    console.log(err || response)
);

有谁知道它在哪里记录了如何传递 api explorer 要求的“请求的正文”?

Q3:为什么google api需要在base64编码中进行替换?

我尝试使用编码

const Base64 = require("js-base64").Base64
var encodedMail = Base64.encode(str);

当我将它输入 API 资源管理器时,我得到了错误

"message": "ByteString 的值无效:

【问题讨论】:

developers.google.com/gmail/api/v1/reference/users/messages/… 在 javascript 选项卡中给出了一个示例,但它显示“不使用客户端库。”。但它没有说它正在使用什么。它会调用 gapi.client.gmail.users.messages.send,但没有说明 gapi 的价值。 在继续之前,您能否检查一下您是否可以在这个SO post 和另一个SO post 中获得一些信息? 感谢您发现更多非常相似的问题。您找到的第一个解决方案建议使用 resource: raw: 是我尝试过的。您找到的第二个解决方案建议多部分/相关,但我试图发送一个简单的“hello world”没有附件,并且当我将编码字符串传递到操场时,内容类型有效。这个 API 绝对可以使用一些文档和一些示例来做一些简单的事情。 就像我在issue tracker说的,你可以参考this SO post ***.com/questions/48579566 似乎是一个几乎相同的问题,未解决,作者建议不要使用googleapi API?当我发布我的问题时,我没有看到这个。 【参考方案1】:

哎呀!对于在这里绊倒的其他人,有几件事。首先 - 我们现在有一个完整的端到端发送邮件示例:

https://github.com/google/google-api-nodejs-client/blob/master/samples/gmail/send.js

其次,上面的答案大多是正确的 :) 而不是安装最新版本的 google-auth-library... 只需将其从您的 package.json 中删除即可。入门指南非常非常错误(现已修复)。 googelapis 引入了它自己的兼容版本 google-auth-library,所以你真的不想通过安装自己的版本来搞砸它:)

【讨论】:

【参考方案2】:

快速入门指定:

npm install google-auth-library@0.* --save

当我把它改成

npm install google-auth-library -- save

它引入了 1.3.1 和 0.12.0 版本。一旦我更改了代码以解决重大更改,一切都开始工作了。最新版本的 googleapis 也有重大变化。这是我对快速入门的调整:

package.json

 ....
  "dependencies": 
    "google-auth-library": "^1.3.1",
    "googleapis": "^26.0.1"
  

quickstart.js

var fs = require('fs');
var readline = require('readline');
var google = require('googleapis');
const GoogleAuth, JWT, OAuth2Client = require('google-auth-library');


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'
];

var TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH ||
    process.env.USERPROFILE) + '/.credentials/';
var TOKEN_PATH = TOKEN_DIR + 'gmail-nodejs-quickstart.json';

function authorize(credentials, callback) 
    var clientSecret = credentials.installed.client_secret;
    var clientId = credentials.installed.client_id;
    var redirectUrl = credentials.installed.redirect_uris[0];
    var auth = new GoogleAuth();
    var oauth2Client = new OAuth2Client(clientId, clientSecret, redirectUrl);

    // Check if we have previously stored a token.
    fs.readFile(TOKEN_PATH, function (err, token) 
        if (err) 
            getNewToken(oauth2Client, callback);
         else 
            oauth2Client.credentials = JSON.parse(token);
            callback(oauth2Client);
        
    );


function getNewToken(oauth2Client, callback) 
    var authUrl = oauth2Client.generateAuthUrl(
        access_type: 'offline',
        scope: SCOPES
    );
    console.log('Authorize this app by visiting this url: ', authUrl);
    var rl = readline.createInterface(
        input: process.stdin,
        output: process.stdout
    );
    rl.question('Enter the code from that page here: ', function (code) 
        rl.close();
        oauth2Client.getToken(code, function (err, token) 
            if (err) 
                console.log('Error while trying to retrieve access token', err);
                return;
            
            oauth2Client.credentials = token;
            storeToken(token);
            callback(oauth2Client);
        );
    );



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 gmail = google.gmail('v1');
    var raw = makeBody('xxxxxxxx@hotmail.com', 'xxxxxxx@gmail.com', 'test subject', 'test message');
    gmail.users.messages.send(
        auth: auth,
        userId: 'me',
        resource: 
            raw: raw
        
    , function(err, response) 
        console.log(err || response)
    );


const secretlocation = 'client_secret.json'

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);
);

现在当我运行时,我得到了响应

Object status: 200, statusText: "OK", headers: Object, config: Object, request: ClientRequest, …

【讨论】:

以上是关于用于在节点 js javascript 文件中发送用户消息的 gmail API的主要内容,如果未能解决你的问题,请参考以下文章

节点 JS 客户端与服务器

在节点 js 服务器中解析表单数据请求

在节点 js 中使用 javascript 函数

如何将数据从html发送到节点js?

Baffle.js – 用于实现文本模糊效果的 JavaScript 库

Javascript - Node.js - 防止函数的多次执行