我在我的无服务器 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 的问题相同。 我现在很困惑......
我遇到了这个问题并设法解决了它,并通过添加带有异步/等待的承诺来继续使用 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" });
};
这个问题确实很迷惑。我已经设法通过简单地添加 async/await 来解决这个问题。这是因为 Vercel 不支持流式响应(即发即弃功能)。
来源:https://vercel.com/docs/platform/limits#streaming-responses
我已经遇到了同样的问题,nodemailer 无法在 vercel 上运行,但在 heroku 上一切正常。文档中指定 vercel 不会阻止 stmp 连接,但根据我的经验,实际上 stmp 连接被阻止。你可以做的是使用 nodemailer 的替代品。使用 sendgrid,它工作正常
我在 Nodemailer 上遇到了类似的问题,但我通过首先在 Vercel 中添加环境变量然后提交到 github(它将自动上传到 Vercel)来修复它。所以先给vercel添加变量让它生效
在我自己的案例中,用异步包装我的电子邮件功能为我解决了这个问题。
例如:
const sendMessage = async(message)=>{
await transporter.sendMail({...options here})
}
然后在我的 API 中,我调用了我的函数:
await sendMessage('your message')
我试了所有
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 })
}
以防将来有人碰到这个:
for nuxt3 in vercel(不是下一个,但它也应该适用)
export default defineEventHandler(async (event) => {
await mailTransport.sendMail(mailOptions);
return {}
}
您需要从 nodemailer sendEmail 函数中删除回调,否则它不会返回承诺...这会导致 vercel 中的脚本提前终止,因此不会发送电子邮件!
如果未设置回调参数,则该方法返回一个 Promise 目的。 Nodemailer 本身不在内部使用 Promises 但它 为了方便起见,将返回值包装成 Promise。