在next/react裡發送email,最常看到的有兩個package,下載次數最多的是nodemalier,其次是emailjs。很多同學會問:「為何要使用email服務?」,當我們的系統透過gmail發送信件時,因為gmail常被拿來當作攻擊的跳板,當大量發信時,通常會被判斷為垃圾信。而這些email服務就是讓我們可以發大量信件而不會被判斷為垃圾信。另外,也提供一些管理功能,例如,可以讓我們轉換郵件服務提供者的時候,不必改寫程式。
以下就以nodemailer以及gmail為例,進行說明。首先,先設定好gmail帳號,透過產生app密碼,產生另一組專門用來透過應用程式發信的密碼 (跟平常登入不一樣的密碼)。
設定好應用程式密碼後,透過npm或yarn安裝package,因為範例是使用typescript,還需要@types/nodemailer,如果使用javascript,就不需要:
npm install nodemailer
npm install @types/nodemailer
通常,為了保護我們的設定,會將設定放在.env.local (如果佈署到vercel,請記得也要在vercel上設定變數)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=465
SMTP_USER=XXXX
SMTP_PASSWORD=XXXX
SMTP_FROM_EMAIL=XXXX
接下來,我們利用next的api寫一個很簡單的發信服務
/pages/api/email_test.ts
import { NextApiHandler, NextApiRequest, NextApiResponse } from "next";
import nodemailer from "nodemailer";
const handler: NextApiHandler = async (
req: NextApiRequest,
res: NextApiResponse
) => {
const smtpOptions = {
host: process.env.SMTP_HOST || "smtp.gmail.com",
port: parseInt(process.env.SMTP_PORT || "465"),
//secure: true,
auth: {
user: process.env.SMTP_USER || "user",
pass: process.env.SMTP_PASSWORD || "password",
},
};
try {
const transporter = nodemailer.createTransport(smtpOptions);
console.log("user:", process.env.SMTP_USER);
await transporter.sendMail({
from: process.env.SMTP_USER || "[email protected]",
to: "[email protected]",
subject: "測試",
html: "測試 gmail",
});
return res.status(200).json({ message: "Email sent successfully" });
} catch (error) {
console.error(error);
}
};
export default handler;
當我們執行這個api時,就能收到email了
要從一般的頁面透過API發送電子郵件,首先,先新增一個測試頁面,讓使用者輸入收件人電子郵件:
import { Button, TextField } from "@mui/material";
import Head from "next/head";
import { useState } from "react";
export default function TestEmail() {
const [email, setEmail] = useState<string>();
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setEmail(e.target.value);
}
return (
<div>
<Head>
<title>email測試</title>
<meta name="description" content="email test" />
<link rel="icon" href="/favicon.ico" />
</Head>
<TextField
type="text"
name="email"
value={email}
placeholder="請輸入信箱..."
onChange={handleChange}
autoComplete="email"
/>
<Button >
送出
</Button>
</div>)
}