我在DigitalOean的应用程序平台上有一个mern应用程序。如果用户注册,他们会收到一封欢迎电子邮件,要求他们验证电子邮件地址。如果他们不这样做,当他们登录时,他们会在个人资料页面上看到一个重新发送验证电子邮件的按钮。
我正在使用 nodemailer 发送电子邮件,目前是通过我的个人帐户(稍后会更改)。它可以在本地主机和 Render.com 上运行,但在数字海洋上我收到以下错误:
Error: Missing credentials for "PLAIN"
[mat-scout] [2023-11-08 02:05:49] at SMTPConnection._formatError (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:790:19)
[mat-scout] [2023-11-08 02:05:49] at SMTPConnection.login (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:444:38)
[mat-scout] [2023-11-08 02:05:49] at /workspace/node_modules/nodemailer/lib/smtp-transport/index.js:272:32
[mat-scout] [2023-11-08 02:05:49] at SMTPConnection.<anonymous> (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:213:17)
[mat-scout] [2023-11-08 02:05:49] at Object.onceWrapper (node:events:627:28)
[mat-scout] [2023-11-08 02:05:49] at SMTPConnection.emit (node:events:513:28)
[mat-scout] [2023-11-08 02:05:49] at SMTPConnection._actionEHLO (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:1347:14)
[mat-scout] [2023-11-08 02:05:49] at SMTPConnection._processResponse (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:969:20)
[mat-scout] [2023-11-08 02:05:49] at SMTPConnection._onData (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:755:14)
[mat-scout] [2023-11-08 02:05:49] at TLSSocket.SMTPConnection._onSocketData (/workspace/node_modules/nodemailer/lib/smtp-connection/index.js:193:44) {
[mat-scout] [2023-11-08 02:05:49] code: 'EAUTH',
[mat-scout] [2023-11-08 02:05:49] command: 'API'
[mat-scout] [2023-11-08 02:05:49] }
我现在尝试添加文本:“Hello World”,但仍然收到错误。这是 mail.js 文件:
import nodemailer from "nodemailer";
import path from "path";
import { fileURLToPath } from "url";
import { generateTemplate } from "../mail/template.js";
const generateMailTransporter = () => {
let transport = nodemailer.createTransport({
host: "smtp.comcast.net",
port: 587,
secure: false,
auth: {
user: process.env.EMAIL,
pass: process.env.EMAIL_PASS,
},
});
return transport;
};
export const sendVerificationEmail = async (token, link, profile) => {
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const transport = generateMailTransporter();
const { firstName, email } = profile;
const welcomeMessage = `Hi ${firstName}, welcome to ! There are so many features available to verified users. Use the given OTP (One-Time-Password) to verify your email.`;
transport.sendMail({
to: email,
from: process.env.VERIFICATION_EMAIL,
subject: "Welcome to MatScout",
text: "hello world",
html: generateTemplate({
title: "Welcome to MatScout",
message: welcomeMessage,
logo: "cid:logo",
banner: "cid:welcome",
link,
btnTitle: "Verify Your Email",
}),
attachments: [
{
fileName: "logo.png",
path: path.join(__dirname, "../mail/logo.png"),
cid: "logo",
},
{
fileName: "welcome.png",
path: path.join(__dirname, "../mail/welcome.png"),
cid: "welcome",
},
],
});
};
export const sendForgotPasswordLink = async (link, profile) => {
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const transport = generateMailTransporter();
const { email } = profile;
const message = `We just received a request to reset your password. Use the link beloow to create a new password. <br><br> If you did not send this request, it means someone is trying to access your account and you can disregard this email.`;
async function main() {
let info = await transport.sendMail({
to: email,
from: process.env.VERIFICATION_EMAIL,
subject: "Reset Password Link",
text: "hello world",
html: generateTemplate({
title: "Forgot Password",
message,
logo: "cid:logo",
banner: "cid:forget_password",
link,
btnTitle: "ResetPassword",
}),
attachments: [
{
fileName: "logo.png",
path: path.join(__dirname, "../mail/logo.png"),
cid: "logo",
},
{
filename: "forget_password.png",
path: path.join(__dirname, "../mail/forget_password.png"),
cid: "forget_password",
},
],
});
}
main().catch(console.error);
};
export const sendPassResetSuccessEmail = async (firstName, email) => {
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const transport = generateMailTransporter();
const message = `Dear ${firstName}, your password has just been reset successfuly. You can now sign in with your new password.`;
transport.sendMail({
to: email,
from: process.env.VERIFICATION_EMAIL,
subject: "Password Reset Successfully!",
text: "hello world",
html: generateTemplate({
title: "Password Reset Successfully",
message,
logo: "cid:logo",
banner: "cid:forget_password",
link: process.env.SIGN_IN_URL,
btnTitle: "Sign In",
}),
attachments: [
{
fileName: "logo.png",
path: path.join(__dirname, "../mail/logo.png"),
cid: "logo",
},
{
filename: "forget_password.png",
path: path.join(__dirname, "../mail/forget_password.png"),
cid: "forgot_password",
},
],
});
};
错误消息表明身份验证详细信息未正确提供给 SMTP 服务器。您可以在
generateMailTransporter
函数内将它们正确记录到控制台吗?
例如:
const generateMailTransporter = () => {
// What does the following output?
console.log('Email:', process.env.EMAIL);
console.log('Email Pass:', process.env.EMAIL_PASS);
let transport = nodemailer.createTransport({
host: "smtp.comcast.net",
port: 587,
secure: false,
auth: {
user: process.env.EMAIL,
pass: process.env.EMAIL_PASS,
},
});
return transport;
};
如果记录正确,我遇到的唯一其他事情是:
a) 一些电子邮件提供商限制云平台的 SMTP 访问以防止滥用。您可能需要使用专用的交易电子邮件服务,例如 SendGrid。
b) 在 DigitalOcean 的应用程序平台上,您可以在应用程序规范中或通过应用程序的“设置”选项卡设置环境变量(秘密)。验证这些设置是否正确并且此处没有任何冲突。
HTH