vercel 中的 Nodemailer 在生产环境中不发送电子邮件

问题描述 投票:0回答:7

我在我的无服务器 Next.js 项目中使用 Nodemailer 发送电子邮件,该项目部署在 Vercel 中,在开发模式下完美运行。但是我在生产中遇到了问题。没有错误返回,一切都与开发模式相同,除了我没有收到任何电子邮件。

我有另一个用 React 构建并部署在 Heroku 中的项目,在那里我以相同的方式发送电子邮件并且它工作正常,开发和生产,所以我知道问题出在 Vercel 上。

是的,我在 Google 帐户中启用了“允许安全性较低的应用程序”,是的,我启用了验证码。

我也读过这个 https://vercel.com/docs/solutions/email 但它并没有真正让我明白我应该做什么。我可以看到这是 SMTP 的问题,但我不知道到底是什么。

有人遇到过这种问题吗?我该如何解决这个问题?

const transporter = nodemailer.createTransport({
    host: "smtp.gmail.com",
    port: 465,
    auth: {
        user: [email protected],
        pass: myEmailPass
    }
});
            
const mailOptions = {
    from: `${req.body.name} ${req.body.email}`,
    to: [email protected],
    subject: `${req.body.subject}`,
    text: `Text: ${req.body.text}`
}
            
transporter.sendMail(mailOptions, (err, res) => {
    if(err) {
          console.log(err);
    } else {
          console.log("success");
    }
});

更新

我更改为 SendGrid:创建一个帐户,创建一个 API 密钥,然后像这样更改代码(而不是上面的代码):

sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
    to: `[email protected]`,
    from: `[email protected]`,
    subject: `${req.body.subject}`,
    text: `${req.body.text}`
};
sgMail
.send(msg)
.then(() => {
     console.log('email sent')
})
.catch((error) => {
     console.error("error", error)
});

它注销“电子邮件已发送”,但我没有收到任何电子邮件。 这与 Nodemailer 的问题相同。 我现在很困惑......

next.js sendgrid nodemailer vercel
7个回答
30
投票

我遇到了这个问题并设法解决了它,并通过添加带有异步/等待的承诺来继续使用 nodemailer。

const nodemailer = require("nodemailer");

export default async (req, res) => {

const { firstName, lastName, email, message } = JSON.parse(req.body);

const transporter = nodemailer.createTransport({
    port: 465,
    host: "smtp.gmail.com",
    auth: {
        user: "[email protected]",
        pass: "password",
    },
    secure: true,
});

await new Promise((resolve, reject) => {
    // verify connection configuration
    transporter.verify(function (error, success) {
        if (error) {
            console.log(error);
            reject(error);
        } else {
            console.log("Server is ready to take our messages");
            resolve(success);
        }
    });
});

const mailData = {
    from: {
        name: `${firstName} ${lastName}`,
        address: "[email protected]",
    },
    replyTo: email,
    to: "[email protected]",
    subject: `form message`,
    text: message,
    html: `${message}`,
};

await new Promise((resolve, reject) => {
    // send mail
    transporter.sendMail(mailData, (err, info) => {
        if (err) {
            console.error(err);
            reject(err);
        } else {
            console.log(info);
            resolve(info);
        }
    });
});

res.status(200).json({ status: "OK" });
};

6
投票

这个问题确实很迷惑。我已经设法通过简单地添加 async/await 来解决这个问题。这是因为 Vercel 不支持流式响应(即发即弃功能)。

来源:https://vercel.com/docs/platform/limits#streaming-responses


2
投票

我已经遇到了同样的问题,nodemailer 无法在 vercel 上运行,但在 heroku 上一切正常。文档中指定 vercel 不会阻止 stmp 连接,但根据我的经验,实际上 stmp 连接被阻止。你可以做的是使用 nodemailer 的替代品。使用 sendgrid,它工作正常

一篇关于如何将 Sendgrid 与 Next.js 集成的文章


2
投票

我在 Nodemailer 上遇到了类似的问题,但我通过首先在 Vercel 中添加环境变量然后提交到 github(它将自动上传到 Vercel)来修复它。所以先给vercel添加变量让它生效


0
投票

在我自己的案例中,用异步包装我的电子邮件功能为我解决了这个问题。

例如:

const sendMessage = async(message)=>{
  await transporter.sendMail({...options here})
}

然后在我的 API 中,我调用了我的函数:

await sendMessage('your message')

0
投票

我试了所有

async/await
的答案,一开始都不行。通过挖掘应用程序的实时
functions
日志,我注意到有一个
Error: Missing credentials for "PLAIN"
,所以我所要做的就是将相应的
.env
变量添加到 vercel 环境变量并且它起作用了。不过,这是完整的代码:

import type { NextApiRequest, NextApiResponse } from 'next'

type Data = any
const nodemailer = require('nodemailer')

const auth = {
  user: process.env.WEB_MAILER,
  pass: process.env.WEB_MAILER_PASSWORD,
}

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Data>
) {
  const { name, email, subject, message } = req.body

  const mailData = {
    to: process.env.EMAIL_TO,
    from: process.env.WEB_MAILER,
    name: name,
    subject: subject,
    text: `Email: ${email}.\n\nMessage: ${message}`,
    html: `<div>Email: ${email}.\n\nMessage: ${message}</div>`,
  }

  const transporter = nodemailer.createTransport({
    host: 'smtp.titan.email',
    secure: true,
    port: 465,
    auth: auth,
  })

  const server = await new Promise((resolve, reject) => {
    // verify connection configuration
    transporter.verify(function (error: any, success: any) {
      if (success) {
        resolve(success)
      }
      reject(error)
    })
  })
  if (!server) {
    res.status(500).json({ error: 'Error failed' })
  }

  const success = await new Promise((resolve, reject) => {
    // send mail
    transporter.sendMail(mailData).then((info: any, err: any) => {
      if (info.response.includes('250')) {
        resolve(true)
      }
      reject(err)
    })
  })

  if (!success) {
    res.status(500).json({ error: 'Error sending email' })
  }
  res.status(200).json({ success: success })
}

0
投票

以防将来有人碰到这个:

for nuxt3 in vercel(不是下一个,但它也应该适用)

export default defineEventHandler(async (event) => {
  await mailTransport.sendMail(mailOptions);

  return {}
}

您需要从 nodemailer sendEmail 函数中删除回调,否则它不会返回承诺...这会导致 vercel 中的脚本提前终止,因此不会发送电子邮件!

如果未设置回调参数,则该方法返回一个 Promise 目的。 Nodemailer 本身不在内部使用 Promises 但它 为了方便起见,将返回值包装成 Promise。

© www.soinside.com 2019 - 2024. All rights reserved.