簡體   English   中英

Nodemailer 自定義 SMTP 不適用於 Firebase 函數

[英]Nodemailer Custom SMTP not working on Firebase Functions

我有一個錯誤。 我正在使用 nodemailer 從我的 Firebase 應用程序發送電子郵件。

這是我的代碼的樣子:

const functions = require('firebase-functions');
const admin = require("firebase-admin");
const nodemailer = require('nodemailer');

admin.initializeApp();

//THESE SETTINGS WORK ON LOCAL AND LIVE. BUT I DONT WANT TO USE THEM
// const transporter = nodemailer.createTransport({
//     service: 'gmail',
//     auth: {
//         user: 'GMAIL HERE',
//         pass:  'GMAIL PW HERE'
//     },
// })

//THESE SETTINGS WORK ON LOCAL, BUT NOT ON LIVE.
const transporter = nodemailer.createTransport({
    host: "smtp.mycompanyname.com",
    port: 25,
    secureConnection: false, // TLS requires secureConnection to be false
    logger: true,
    debug: true,
    secure: false,
    requireTLS: true,
    auth: {
        user: "USERNAME HERE",
        pass: "PASSWORD HERE"
    },
    tls: { rejectUnauthorized: false }
})

exports.sendConfirmationEmail = functions.https.onCall((data, context) => {

    var email_adress        = data.data.email;

    var email = {
        from: 'E-Mail Adress Goes Here',
        to: email_adress,
        subject: 'BlaBlaBla',
        text: 'BlaBlaBla',
        html: 'BlaBlaBla'
    };
    // Function to send e-mail to the user
    transporter.sendMail(email, function(err, info) {
        if (err) {
            console.log(err);
            return { success: false };
        } else {
            return { success: true }
        }
    });

})

現在。 如果我使用 GMail 設置。 一切正常。 它發送電子郵件。 但是,我的公司有一個自己的 SMTP 服務器。 SMTP 適用於 Firebase 身份驗證電子郵件。 它正在成功發送這些電子郵件。

當我將上述配置粘貼到本地環境中時,SMTP 服務器也可以工作。 但是,當我在 Firebase Cloud 函數中運行它時,它給了我以下錯誤:

10:24:43.479 AM
sendConfirmationEmail
[2020-09-25 08:24:43] DEBUG [Cq6p67HnXLA] Closing connection to the server using "destroy"
10:24:43.479 AM
sendConfirmationEmail
[2020-09-25 08:24:43] ERROR Send Error: Connection timeout
10:24:44.673 AM
sendConfirmationEmail
{ Error: Connection timeout
10:24:44.673 AM
sendConfirmationEmail
    at SMTPConnection._formatError (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:784:19) 
10:24:44.674 AM
sendConfirmationEmail
    at SMTPConnection._onError (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:770:20) 
10:24:44.674 AM
sendConfirmationEmail
at Timeout._connectionTimeout.setTimeout (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:235:22)

我嘗試使用不同的 nodemailer 選項,但到目前為止還沒有取得多大成功。 這也使得它在本地工作變得困難,但是當我部署它時卻沒有。

有任何想法嗎?

我遇到了完全相同的問題,需要進行一些挖掘,但解決方案非常簡單。

解決方案


不能在 Cloud Function 中的端口 25上使用出站連接。


所以我將端口更改為 465 並使用安全連接,它確實有效。

我在Tips & Tricks文檔頁面(隨機)發現了這個。

PS:同樣的限制適用於 Compute Engine(請參閱文檔)。

您應該使用 Promises 來管理 Cloud Functions 的生命周期,它執行一個異步操作並返回一個 promise(即sendMail()方法)。 有關更多詳細信息,請參閱此 文檔

因此,通過使用sendMail()方法返回的承諾而不是回調,它應該可以工作,如下所示。

exports.sendConfirmationEmail = functions.https.onCall((data, context) => {

    var email_adress = data.data.email;

    var email = {
        from: 'E-Mail Adress Goes Here',
        to: email_adress,
        subject: 'BlaBlaBla',
        text: 'BlaBlaBla',
        html: 'BlaBlaBla'
    };

    return transporter.sendMail(email).then(() => {  // Note the return here
        return { success: false };
    }).catch(error => {
        console.log(error);
        // !! Here, return an instance of functions.https.HttpsError.
        // See the doc: https://firebase.google.com/docs/functions/callable#handle_errors
    });

});

注意:如果您使用的不是Node.js 10 或 12,而是 Node.js 8(我猜不是這種情況,因為自 2020 年 2 月 15 日起不再允許部署 Node.js 8 功能。),請閱讀以下內容:

如果您在 Cloud Function 中使用 Node.js 版本 8,請注意您需要使用“Blaze”定價計划。 事實上,免費的“Spark”計划“只允許對谷歌擁有的服務的出站網絡請求”。 請參閱https://firebase.google.com/pricing/ (將鼠標懸停在“雲函數”標題后面的問號上)

由於您的 SMTP 服務器不是 Google 擁有的服務,因此您需要切換到“Blaze”計划。

  1. 火焰是必需的
  2. 端口25不起作用
  3. Node.js 12確實有效
  4. tls: { rejectUnauthorized: false }是使其工作必不可少的

下面的工作( TypeScript )代碼,用例是一個聯系表單。

import * as functions from 'firebase-functions';
import * as nodemailer from 'nodemailer';
import * as Mail from 'nodemailer/lib/mailer';
import { DocumentSnapshot } from 'firebase-functions/lib/providers/firestore';
import { EventContext } from 'firebase-functions';

async function onCreateSendEmail(
  snap: DocumentSnapshot,
  _context: EventContext
) {
  try {
    const contactFormData = snap.data();
    console.log('Submitted contact form: ', contactFormData);
    console.log('context: ', _context);

    // The non-null assertion signs (!) might be not required, if your IDE/TypeScript settings aren't strict.
    const mailTransport: Mail = nodemailer.createTransport({
      host: 'mail.yourdomain.com', // Or however your SMTP provides defines it.
      port: 587, // Most probably that's your port number.
      auth: {
        user: 'yourmail@domain.com', // It could happen that your SMTP provides in user authentication requires full name of mail account. For example 'yourmail' would be not correct, 'yourmail@domain.com' would.
        pass: 'YOUR_MAIL_PASSWORD',
      },
      tls: {
        rejectUnauthorized: false, //! ESSENTIAL! Fixes ERROR "Hostname/IP doesn't match certificate's altnames".
      },
    });

    const mailOptions = {
      from: `${contactFormData!.formControlName} <${
        contactFormData!.formControlEmail
      }>`,
      to: 'yourmail@domain.com',
      subject: `Contact Form`,
      html: `
        <p>Message from a contact form has been send.</p>
        <h3>Message content:</h3>
        <ul>
          <li>Name: ${contactFormData!.formControlName}</li>
          <li>E-mail: ${contactFormData!.formControlEmail}</li>
          ...
        </ul>
      `,
    };

    await mailTransport.sendMail(mailOptions);
  } catch (err) {
    console.error(err);
  }
}

exports.contactFormFunction = functions.firestore
  .document('mails/{formControlEmail}'
  )
  .onCreate(onCreateSendEmail);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM