跳到主要内容

邮件订阅

一个常见的邮件定义功能组件一般长这样:一个用于输入邮箱地址的输入框,和一个用于触发提交的按钮。

邮件订阅

我们只需要给按钮绑定一个方法,将输入的邮件地址通过一个变量存储后,提交给后端的接口:

const subscribe = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const res = await fetch("/api/subscribe", {
body: JSON.stringify({
email: value,
}),
headers: {
"Content-Type": "application/json",
},
method: "POST",
});

const { error } = await res.json();

if (error) {
// Error to do
}
// Success to do
};

如果邮件订阅的数据需要我们自己存储,那么我们就需要写一个接口来实现,这里以使用 Prisma 为例:

创建用于存储订阅邮箱的 Prisma 数据模型:

model Subscriber {
id Int @id @default(autoincrement())
email String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

订阅接口实现:

先判断邮箱是否已存在,然后更新数据表。

import { NextApiRequest, NextApiResponse } from 'next';

import prisma from '@/common/libs/prisma';

export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const { email } = req.body;

try {
const existingSubscriber = await prisma.subscriber.findUnique({
where: { email }
});

if (existingSubscriber) {
return res.status(400).json({ error: 'Email already exists' });
}

const subscriber = await prisma.subscriber.update({
data: { email }
});

return res.json(subscriber);
} catch (error) {
return res.status(500).json({ error: 'Failed to subscribe' });
}
}

如果我们是借助第三方的服务来实现邮箱订阅功能,这里以 Convertkit 服务提供商为例,它的调用方式如下:

import type { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { email } = req.body;

if (!email) {
return res.status(400).json({ error: "Email is required" });
}

try {
const FORM_ID = process.env.CONVERTKIT_FORM_ID;
const API_KEY = process.env.CONVERTKIT_API_KEY;

const data = {
email,
api_key: API_KEY,
};

const response = await fetch(
`https://api.convertkit.com/v3/forms/${FORM_ID}/subscribe`,
{
body: JSON.stringify(data),
headers: {
Authorization: `apikey ${API_KEY}`,
"Content-Type": "application/json; charset=utf-8",
},
method: "POST",
}
);
if (response.status >= 400) {
return res.status(400).json({
error: `There was an error subscribing to the newsletter…`,
});
}

return res.status(201).json({ error: "" });
} catch (error: any) {
return res.status(500).json({ error: error.message || error.toString() });
}
}