首页 > 解决方案 > 发送邮件()上的Nodemailer w Google Mail服务帐户错误

问题描述

我正在尝试从 Firebase 功能发送电子邮件,此时我可以获得 jwt 客户端、授权 iy、获取令牌并创建 nodemailer 传输器。但是尝试执行 transporter.sendmail(),我得到一个错误:

info: { Error: Invalid status code 401
        at ClientRequest.req.on.res (/Users/yves/Developments/WIP/VUE.JS-vcli-3-beta/le-choro-des-charentes/functions/node_modules/nodemailer/lib/fetch/index.js:221:23)
        at emitOne (events.js:116:13)
        at ClientRequest.emit (events.js:211:7)
        at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:551:21)
        at HTTPParser.parserOnHeadersComplete (_http_common.js:117:23)
        at TLSSocket.socketOnData (_http_client.js:440:20)
        at emitOne (events.js:116:13)
        at TLSSocket.emit (events.js:211:7)
        at addChunk (_stream_readable.js:263:12)
        at readableAddChunk (_stream_readable.js:250:11)
      type: 'FETCH',
      sourceUrl: 'https://accounts.google.com/o/oauth2/token',
      code: 'EAUTH',
      command: 'AUTH XOAUTH2' }

在阅读了很多帖子(在许多不同情况下的问答)之后,我迷失了......我的感觉是这个错误可能与 refresk 令牌有关......但谁知道呢?

这是我的函数(我插入了一些 console.log 来观察它的进展......,所有的环境变量都设置为 w functions.config()):

    const functions = require('firebase-functions');
    const admin = require('firebase-admin');
    admin.initializeApp();

    const { google } = require('googleapis')
    const nodemailer = require('nodemailer')

    exports.sendContactEmailOAuth = functions.https.onRequest((req, res) => {
      const sender_email = 'john.doe@acme.com';
      const sender_msg = 'just a test to contact the site owner.'
      const email = 'contact@example.com'

      const jwtClient = new google.auth.JWT({
        email: functions.config().service_key.client_email,
        key: functions.config().service_key.private_key,
        scopes: ['https://mail.google.com/']
        }
      )

      console.log('JWT Client: ', jwtClient)

      jwtClient.authorize((error, tokens) => {
        if (error) {
          console.log('NOT AUTHORIZE?: ', error)
          res.json({ success: false, error: error });
          return
        }
        console.log('AUTHORIZED tokens: ', tokens)

        var transporter = nodemailer.createTransport({
          host: "smtp.gmail.com",
          port: 465,
          secure: true,
          auth: {
            type: 'OAuth2',
            user: email,
            serviceClient: functions.config().service_key.client_id,
            privateKey: functions.config().service_key.private_key,
            accessToken: tokens.access_token,
            refreshToken: tokens.refresh_token,
            expires: tokens.expiry_date
          }
        });

        console.log('nodemailer transporter set...');

        const mailOptions = {
          from: 'An Example<' + sender_email + '>',
          to: email,
          subject: 'Apple and Banana',
          text: sender_msg,
          html: '<h1>Apple and Banana</h1><p>My html here</p>'
        };

        transporter.sendMail(mailOptions, (error, response) => {
          if (error) {
            console.log(error);
            res.end('error');
          } else {
            console.log("Message sent: " + response.message);
            res.end('sent');
          }
          transporter.close();
        });
      });
    });

现在我可以看到控制台输出:

    =====================

    info: User function triggered, starting execution

    info: JWT Client:  JWT {
      domain: null,
      _events: {},
      _eventsCount: 0,
      _maxListeners: undefined,
      transporter: DefaultTransporter {},
      credentials: { refresh_token: 'jwt-placeholder', expiry_date: 1 },
      certificateCache: null,
      certificateExpiry: null,
      refreshTokenPromises: Map {},
      _clientId: undefined,
      _clientSecret: undefined,
      redirectUri: undefined,
      authBaseUrl: undefined,
      tokenUrl: undefined,
      eagerRefreshThresholdMillis: 300000,
      email: 'postman@example-209605.iam.gserviceaccount.com',
      keyFile: undefined,
      key: '-----BEGIN PRIVATE KEY-----\nMIIEvAI........IZFwQg==\n-----END PRIVATE KEY-----\n',
      scopes: [ 'https://mail.google.com/' ],
      subject: undefined,
      additionalClaims: undefined }

    info: AUTHORIZED tokens:  { access_token: 'ya29.c.Elm6BYmTEQ6B82VWaAVx-9oXxX0ytUhgag-FJNPzFl1R9zEeeQQsGuMB5XnMrnbRRZBQuJkprvW1E_Sh8spyEmbd4iwAXbaj2Ou9vcww',
      token_type: 'Bearer',
      expiry_date: 1526217245000,
      id_token: undefined,
      refresh_token: 'jwt-placeholder' }

    info: nodemailer transporter set...

        info: { Error: Invalid status code 401
            at ClientRequest.req.on.res (/Users/myself/Developments/myapp/functions/node_modules/nodemailer/lib/fetch/index.js:221:23)
            at emitOne (events.js:116:13)
            at ClientRequest.emit (events.js:211:7)
            at HTTPParser.parserOnIncomingClient [as onIncoming] (_http_client.js:551:21)
            at HTTPParser.parserOnHeadersComplete (_http_common.js:117:23)
            at TLSSocket.socketOnData (_http_client.js:440:20)
            at emitOne (events.js:116:13)
            at TLSSocket.emit (events.js:211:7)
            at addChunk (_stream_readable.js:263:12)
            at readableAddChunk (_stream_readable.js:250:11)
          type: 'FETCH',
          sourceUrl: 'https://accounts.google.com/o/oauth2/token',
          code: 'EAUTH',
          command: 'AUTH XOAUTH2' }
  1. jwt 客户端好吗?我猜一个座位是授权的。
  2. 代币还好吗?id_token:未定义和 refresh_token:'jwt-placeholder'?
  3. 这个无效的状态码 401 是什么意思?

感谢您的反馈。我离启动和运行它不远了,但这是经过漫长的 GMail 服务帐户身份验证之后的最后一个问题。

标签: node.jsfirebasegoogle-cloud-functionsgmail-apinodemailer

解决方案


推荐阅读