Chuyển tới nội dung chính

SMTP relay

SMTP relay cho phép mọi ứng dụng biết gửi thư qua SMTP dùng Hạ Tầng: WordPress, Laravel, Django, Rails, Spring Boot, một server Postfix, thậm chí máy in. Thư đi qua đúng các bước kiểm tra như POST /emails, nên cũng hiện ở Email → Email với trạng thái, sự kiện và webhook.

Trước khi bắt đầu​

  • Một tên miền đã xác minh cho địa chỉ From. Xem Tên miền.
  • API key có phạm vi email:send. Key này chính là mật khẩu SMTP.

Thông tin kết nối​

Thiết lậpGiá trị
Hostsmtp.hatang.dev
Cổng5870
Mã hoáSTARTTLS (kết nối bắt đầu ở dạng thường rồi nâng cấp bằng lệnh STARTTLS)
Tên đăng nhậphatang
Mật khẩuAPI key của bạn, ht_...
Xác thựcPLAIN hoặc LOGIN

Các giá trị này cũng có ở Cài đặt email → Thông tin kết nối trong dashboard.

Cổng 5870 dùng STARTTLS, không phải TLS ngầm định

Đừng bật "SSL", "implicit TLS" hay secure: true cho cổng 5870: client sẽ bắt tay TLS trước khi server chào và bị treo cho tới khi hết thời gian chờ. Hãy chọn STARTTLS, có ứng dụng gọi là "TLS". Server từ chối xác thực cho tới khi kết nối đã được nâng cấp bằng STARTTLS, nên API key không bao giờ đi qua mạng ở dạng rõ.

Hạ Tầng đọc thư thế nào​

Phần của thưHạ Tầng xử lý ra sao
Header FromNgười gửi. Tên miền phải đã xác minh và thuộc doanh nghiệp của API key. Không có header From thì dùng envelope sender (MAIL FROM).
Header To và CcNgười nhận to và cc.
Người nhận trong envelope (RCPT TO) không có trong To hay CcGửi dưới dạng bcc.
Reply-To, Subject, phần HTML và văn bản, tệp đính kèm, ảnh nhúngGiữ nguyên.
Message-IDGiữ nguyên, nên các chuỗi thư trong hệ thống của bạn vẫn khớp.
Header bắt đầu bằng X-Chuyển tiếp như header riêng, giống trường headers của API. Các header riêng khác bị bỏ.
X-TagsĐược đọc thành tag và không chuyển tiếp. Giá trị là một mảng JSON: X-Tags: [{"name":"category","value":"welcome"}]. Giá trị không phải JSON hợp lệ bị bỏ qua.
Luôn điền To

Nếu thư chỉ có người nhận Bcc, Hạ Tầng chuyển người đầu tiên sang To, nơi mọi người nhận khác đều thấy. Hãy đặt ít nhất một địa chỉ trong header To.

Giới hạn​

Giới hạnGiá trị
Người nhận mỗi thư50 người nhận trong envelope (RCPT TO)
Kích thước thưThư trên 40 MB bị từ chối.
Đăng nhập saiSau 10 lần đăng nhập sai từ một địa chỉ IP, mọi lần đăng nhập từ địa chỉ đó bị từ chối cho tới khi đủ 15 phút kể từ lần sai cuối cùng.
Hạn mức ngàyDùng chung với API: mỗi thư tính là một email.

Mã phản hồi SMTP​

Phản hồiMã mở rộngÝ nghĩaCần làm gì
2502.0.0Đã nhận. Phần chữ kết thúc bằng queued as <id email>.Không cần làm gì.
5305.7.0Cần đăng nhập.Đăng nhập trước lệnh MAIL FROM.
5355.7.8API key sai hoặc đã bị thu hồi.Kiểm tra mật khẩu.
4214.7.0Quá nhiều lần đăng nhập sai từ địa chỉ IP của bạn.Sửa mật khẩu và chờ rồi mới thử lại.
4525.5.3Quá 50 người nhận.Tách thư ra.
5505.7.1Tên miền của From chưa xác minh hoặc không thuộc doanh nghiệp, API key bị giới hạn vào tên miền khác, hoặc doanh nghiệp đang tạm dừng gửi. Phần chữ nói rõ lý do.Xác minh tên miền hoặc sửa địa chỉ From.
5535.6.0Thư bị từ chối vì không hợp lệ, ví dụ header From sai.Sửa thư. Gửi lại y nguyên sẽ lại lỗi.
4514.3.0Lỗi tạm thời, kể cả khi đã hết hạn mức ngày.Thử lại sau. Các mail server như Postfix tự thử lại.

Kiểm tra kết nối​

Kiểm tra STARTTLS hoạt động:

openssl s_client -starttls smtp -connect smtp.hatang.dev:5870 -crlf -quiet

Gửi thư thử bằng swaks:

swaks --server smtp.hatang.dev:5870 --tls \
--auth PLAIN --auth-user hatang --auth-password "$HATANG_API_KEY" \
--header "Subject: Thử SMTP" --body "Chạy rồi."

Hoặc bằng thư viện chuẩn của Python:

import os
import smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "Shop <[email protected]>"
msg["To"] = "[email protected]"
msg["Subject"] = "Thử SMTP"
msg["X-Tags"] = '[{"name":"category","value":"test"}]'
msg.set_content("Chạy rồi.")

with smtplib.SMTP("smtp.hatang.dev", 5870) as smtp:
smtp.starttls()
smtp.login("hatang", os.environ["HATANG_API_KEY"])
smtp.send_message(msg)

Cấu hình mẫu​

Nodemailer​

import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
host: "smtp.hatang.dev",
port: 5870,
secure: false, // bắt buộc là false: cổng 5870 dùng STARTTLS
requireTLS: true, // không gửi nếu không nâng cấp được STARTTLS
auth: { user: "hatang", pass: process.env.HATANG_API_KEY },
});

const info = await transporter.sendMail({
from: "Shop <[email protected]>",
subject: "Chào mừng bạn đến với Shop",
html: "<p>Chào mừng!</p>",
text: "Chào mừng!",
headers: { "X-Tags": JSON.stringify([{ name: "category", value: "welcome" }]) },
});
console.log(info.response); // 250 2.0.0 Ok: queued as <id email>

secure: true nghĩa là TLS ngầm định và không chạy trên cổng 5870.

Laravel​

Trong .env:

MAIL_MAILER=smtp
MAIL_HOST=smtp.hatang.dev
MAIL_PORT=5870
MAIL_USERNAME=hatang
MAIL_PASSWORD=ht_123...
MAIL_FROM_ADDRESS=[email protected]
MAIL_FROM_NAME="Shop"

Mailer của Laravel tự nâng cấp kết nối bằng STARTTLS khi server hỗ trợ, và smtp.hatang.dev luôn hỗ trợ. Để trống MAIL_SCHEME hoặc đặt là smtp; đừng dùng smtps. Với Laravel 10 trở về trước, đặt MAIL_ENCRYPTION=tls.

Django​

Trong settings.py:

import os

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.hatang.dev"
EMAIL_PORT = 5870
EMAIL_HOST_USER = "hatang"
EMAIL_HOST_PASSWORD = os.environ["HATANG_API_KEY"]
EMAIL_USE_TLS = True # STARTTLS
EMAIL_USE_SSL = False # TLS ngầm định: phải tắt
DEFAULT_FROM_EMAIL = "Shop <[email protected]>"

Ruby on Rails​

Trong config/environments/production.rb:

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: "smtp.hatang.dev",
port: 5870,
user_name: "hatang",
password: ENV.fetch("HATANG_API_KEY"),
authentication: :plain,
enable_starttls_auto: true
}

Spring Boot​

Trong application.properties:

spring.mail.host=smtp.hatang.dev
spring.mail.port=5870
spring.mail.username=hatang
spring.mail.password=${HATANG_API_KEY}
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true

WordPress (WP Mail SMTP)​

Cài plugin WP Mail SMTP, mở WP Mail SMTP → Settings và chọn mailer Other SMTP:

Thiết lậpGiá trị
From EmailMột địa chỉ trên tên miền đã xác minh, ví dụ [email protected]. Bật Force From Email.
SMTP Hostsmtp.hatang.dev
EncryptionTLS (trong WP Mail SMTP, đây là STARTTLS)
SMTP Port5870
Auto TLSBật
AuthenticationBật
SMTP Usernamehatang
SMTP PasswordAPI key của bạn

Để không lưu key trong database, khai báo trong wp-config.php:

define( 'WPMS_ON', true );
define( 'WPMS_MAILER', 'smtp' );
define( 'WPMS_SMTP_HOST', 'smtp.hatang.dev' );
define( 'WPMS_SMTP_PORT', 5870 );
define( 'WPMS_SSL', 'tls' );
define( 'WPMS_SMTP_AUTH', true );
define( 'WPMS_SMTP_USER', 'hatang' );
define( 'WPMS_SMTP_PASS', 'ht_123...' );
define( 'WPMS_MAIL_FROM', '[email protected]' );
define( 'WPMS_MAIL_FROM_FORCE', true );

Sau đó gửi thử ở WP Mail SMTP → Tools → Email Test.

PHPMailer​

<?php
use PHPMailer\PHPMailer\PHPMailer;

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.hatang.dev';
$mail->Port = 5870;
$mail->SMTPAuth = true;
$mail->Username = 'hatang';
$mail->Password = getenv('HATANG_API_KEY');
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->CharSet = 'UTF-8';

$mail->setFrom('[email protected]', 'Shop');
$mail->addAddress('[email protected]');
$mail->Subject = 'Chào mừng bạn đến với Shop';
$mail->isHTML(true);
$mail->Body = '<p>Chào mừng!</p>';
$mail->AltBody = 'Chào mừng!';
$mail->addCustomHeader('X-Tags', '[{"name":"category","value":"welcome"}]');
$mail->send();

Postfix relayhost​

Để mọi thư từ một server đi qua Hạ Tầng, đặt Hạ Tầng làm relay host trong /etc/postfix/main.cf:

relayhost = [smtp.hatang.dev]:5870
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt

Ghi thông tin đăng nhập vào /etc/postfix/sasl_passwd:

[smtp.hatang.dev]:5870 hatang:ht_123...

Sau đó khoá quyền tệp và nạp lại:

sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap /etc/postfix/sasl_passwd
sudo systemctl reload postfix

Chỉ thư có địa chỉ From trên tên miền đã xác minh mới được nhận. Hãy đổi người gửi của thư hệ thống (ví dụ bằng smtp_generic_maps) để root@localhost thành một địa chỉ trên tên miền của bạn.

Bước tiếp theo​

Xem trang này dạng Markdown