Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Отправка писем

Блогу нужны письма: приветствие после регистрации, уведомление автору о новом комментарии. В AdonisJS их отправляет пакет @adonisjs/mail. Текст письма — обычный шаблон Edge, а сам способ доставки (SMTP, Mailgun, Resend и другие) выбирается в настройках.

Установка

node ace add @adonisjs/mail

Команда спросит, какие сервисы доставки подключить, — для начала выберите SMTP. Появится config/mail.ts, а в .env — переменные:

SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=blog@example.com
SMTP_PASSWORD=secret

Для разработки удобен сервис-ловушка вроде Mailpit или Mailtrap: он принимает письма по SMTP и показывает их в браузере, никому не отправляя.

Шаблон письма

{{-- resources/views/emails/welcome.edge --}}
<h1>Здравствуйте, {{ user.fullName }}!</h1>
<p>Спасибо за регистрацию в нашем блоге.</p>
<p><a href="https://example.com/posts">Читать статьи</a></p>

В письме ссылки пишут полным адресом с доменом: почтовая программа не знает, с какого сайта пришло письмо.

Отправка

// app/controllers/register_controller.ts
import mail from '@adonisjs/mail/services/main'
 
await mail.send((message) => {
  message
    .to(user.email)
    .from('blog@example.com')
    .subject('Добро пожаловать в блог')
    .htmlView('emails/welcome', { user })
})

Функция получает объект message и настраивает его цепочкой: получатель, отправитель, тема и HTML из шаблона с данными. После регистрации письмо придёт на указанную почту.

Отправка в фоне

mail.send ждёт, пока SMTP-сервер примет письмо, и посетитель всё это время смотрит на загрузку страницы. Метод sendLater ставит письмо в очередь и сразу возвращает управление:

// app/controllers/register_controller.ts
await mail.sendLater((message) => {
  message.to(user.email).subject('Добро пожаловать в блог').htmlView('emails/welcome', { user })
})

По умолчанию очередь хранится в памяти процесса: письма уходят сразу после ответа, но пропадут, если сервер перезапустится.

Класс письма

Когда одно письмо отправляют из разных мест, его оформляют классом:

node ace make:mail welcome
// app/mails/welcome_notification.ts
import { BaseMail } from '@adonisjs/mail'
import User from '#models/user'
 
export default class WelcomeNotification extends BaseMail {
  from = 'blog@example.com'
  subject = 'Добро пожаловать в блог'
 
  constructor(private user: User) {
    super()
  }
 
  prepare() {
    this.message.to(this.user.email).htmlView('emails/welcome', { user: this.user })
  }
}
// app/controllers/register_controller.ts
import WelcomeNotification from '#mails/welcome_notification'
 
await mail.sendLater(new WelcomeNotification(user))

Теперь всё о письме собрано в одном файле, а в контроллере остаётся одна строка.

Частая ошибка

Адрес отправителя в from не совпадает с доменом, к которому привязан SMTP-аккаунт. Почтовые сервисы считают такие письма поддельными, и они попадают в спам или вовсе отклоняются. Отправляйте с адреса на своём домене, например blog@example.com, и настройте для домена записи SPF и DKIM.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.