Это сообщение было впервые опубликовано в моем личном блоге. https://www.nazha.co/posts/revue-alternative

В прошлом году я написал статью (на китайском языке) о том, как создать информационный бюллетень с помощью Next.js и Revue. Но, к сожалению, в начале года Илон Маск закрыл Ревю.

Попробовав Substck, ConvertKit, mailerlite и MailChimp, MailChimp выиграл для меня, потому что:

  • Бесплатный план, который подходит для личного запуска, позволяет до 500 контактов и 2500 ежемесячных отправлений.
  • Даже если у вас бесплатный план, он предлагает API. Если у вас уже есть личный веб-сайт, вам не понадобится еще один для хранения ваших информационных бюллетеней.

Настройка мейлчимпа

После создания бесплатной учетной записи вам нужно будет получить свой ключ API。и другие значения, которые вам нужно будет получить:

  • Регион сервера API. Войдите в свою учетную запись Mailchimp и посмотрите URL-адрес в браузере. Вы увидите что-то вроде https://us19.admin.mailchimp.com/; часть us19 — это регион сервера.

Добавьте секреты в переменные среды

Давайте хранить ваши секреты в переменных окружения, не запрограммировав их и не раскрывая публично. Если вы используете Next.js и выполняете развертывание с помощью Vercel, вы можете:

MAILCHIMP_API_DC=usxx
MAILCHIMP_API_KEY=dbxxxxxxxxxxxxxxxxxxx-usxx
MAILCHIMP_API_AUDIENCE_ID=30xxxxxx

Не забудьте добавить .env.local к .gitignore. Мы не хотим раскрывать наши секреты.

Создание запроса на подписку

Мы можем создать маршрут API в pages/api/subscribe.js, чтобы добавить участника в наш список.

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

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const { email } = req.body;
  res.setHeader('Access-Control-Allow-Origin', '*');
  if (!email) {
    return res.status(400).json({
      error: 'Email is required'
    });
  }
  // <https://mailchimp.com/developer/marketing/api/list-members/>
  const revRes = await fetch(
    `https://${process.env.MAILCHIMP_API_DC}.api.mailchimp.com/3.0/lists/${process.env.MAILCHIMP_API_AUDIENCE_ID}/members`,
    {
      method: 'POST',
      headers: {
        Authorization: `anystring ${process.env.MAILCHIMP_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        email_address: email,
        status: 'subscribed',
        tags: ['xxx'] // If you wanna add some tags
      })
    }
  );
  const data = await revRes.json();
  if (data.status >= 400) {
    return res.status(500).json({
      error: data?.detail ?? 'Something went wrong'
    });
  }
  return res.status(200).json({ error: '' });
}

Создание компонента подписки

Нам нужен компонент для отправки запроса к нашему API для сбора электронной почты пользователя.

import Image from 'next/image';
import React, { FormEvent, useRef, useState } from 'react';

const LoadingSVG = () => {
  return (
    <div>
      <svg
        xmlns="<http://www.w3.org/2000/svg>"
        viewBox="0 0 19 17"
        className="fill-white dark:fill-white"
        width="20"
        height="20">
        <circle className="loadingCircle" cx="2.2" cy="10" r="1.6" />
        <circle className="loadingCircle" cx="9.5" cy="10" r="1.6" />
        <circle className="loadingCircle" cx="16.8" cy="10" r="1.6" />
      </svg>
    </div>
  );
};

const Subscribe = () => {
  const inputEl = useRef<HTMLInputElement>(null);
  const [errMsg, setErrMsg] = useState('');
  const [loading, setLoading] = useState(false);
  
  const subscribe = async (e: FormEvent) => {
    e.preventDefault();
    setLoading(true);
    const res = await fetch('/api/subscribe', {
      body: JSON.stringify({
        email: inputEl?.current?.value
      }),
      headers: {
        'Content-Type': 'application/json'
      },
      method: 'POST'
    });
    setLoading(false);
    const json = await res.json();
    const { error } = json;
    if (error) {
      setErrMsg(error);
      return;
    }
    if (inputEl?.current?.value) {
      inputEl.current.value = '';
    }
    setErrMsg('Success! 🎉 You are now subscribed to the newsletter.');
  };
  return (
    <div className="w-full p-4 mt-10 fontOutfit">
      <div className="flex justify-between items-center">
        <div>
          <Image
            className="w-8 h-8 rounded-full overflow-hidden"
            src="/portrait/logo.jpg"
            alt="portrait"
            width="100px"
            height="100px"
          />
        </div>
        <div className="max-w-[55ch]">
          <p className="font-medium text-sm">Have a weekly visit of</p>
          <p className="font-bold text-2xl bg-gradient-to-r from-subscribleRight to-subscrible bg-clip-text text-transparent">
            Howl&apos;s Moving Castle
          </p>
          <p className="font-light mt-4">
            Get emails from me about web development, tech, and early access to new articles. I will
            only send emails when new content is posted.
          </p>
          <p className="font-bold">Subscribe Now!</p>
        </div>
      </div>
      <div>
        <form className="relative mt-4 border rounded" onSubmit={subscribe}>
          <input
            className="px-4 py-2 block w-full border-gray-300 rounded-md bg-white dark:bg-bg text-gray-900 dark:text-gray-100 pr-32 outline-none"
            ref={inputEl}
            placeholder="Your e-mail address"
            type="email"
            autoComplete="email"
            required
          />
          <button
            type="submit"
            className="bg-gradient-to-r from-subscribleRight to-subscrible flex items-center justify-center absolute right-1 top-1 px-4 py-1 font-medium bg-subscrible text-white rounded w-28 h-9">
            {loading ? <LoadingSVG /> : 'SUBSCRIBE'}
          </button>
        </form>
        {errMsg && <div className="mt-4 text-gray-500 text-sm">{errMsg}</div>}
      </div>
    </div>
  );
};
export default Subscribe;

В итоге мы получаем сцену, похожую на приведенную ниже:

сыр 🧀

Мы можем встраивать кампании Mailchimp в наши отдельные веб-сайты. Погрузитесь во весь исходный код моего блога с открытым исходным кодом.