Gửi mail từ app self-hosted không cần mail server
Cấu hình một SMTP relay ở cấp host cho app self-hosted, thêm SPF, DKIM, DMARC và xử lý lỗi bị chặn port 25 mà không cần chạy mail server.
Những ứng dụng self-hosted nào cần gửi mail
Để gửi mail từ các ứng dụng self-hosted, bạn không cần mail server. Bạn cần một relay: một tài khoản SMTP đã xác thực, được cấu hình một lần trên host, để mọi ứng dụng trên máy gửi mail đi qua đó. Vận hành mailbox mới là phần khó, và đó là một bài toán khác.
Nhận mail nghĩa là chấp nhận kết nối từ toàn bộ Internet trên port 25, lọc spam, lưu trữ và backup mailbox, đồng thời bảo vệ reputation của IP trong suốt thời gian server tồn tại. Công việc đó thực sự ngày càng khó hơn. Gửi mail là gửi password reset, xác nhận đăng ký, cảnh báo "backup failed" và thông báo có trả lời trên forum. Những mail này ngắn, có volume thấp và được gửi lần lượt. Relay xử lý chúng, còn việc thiết lập thường chỉ mất một buổi chiều.
Hãy xác định bạn thực sự đang cần giải quyết bài toán nào trong hai bài toán này. Việc tự vận hành mailbox còn đáng làm hay không là một câu hỏi thực tế và có câu trả lời rõ ràng. Với đa số mọi người, câu trả lời là không. Nếu câu trả lời của bạn là có, một mail server Mailcow đầy đủ trên VPS là hướng triển khai phù hợp. Phần còn lại, tức việc gửi mail, là nhu cầu của gần như mọi người nhưng gần như không ai lên kế hoạch cho nó.
Trước tiên cần hiểu 2 thuật ngữ. SMTP (simple mail transfer protocol) là protocol được mọi thành phần trong hệ thống này sử dụng. Relay, còn gọi là smarthost, là server nhận mail đã xác thực của bạn rồi chuyển tiếp mail bằng các địa chỉ và reputation của chính nó.
Vì sao VPS của bạn không thể gửi mail qua port 25
Hầu hết nhà cung cấp VPS mặc định chặn TCP outbound port 25. Mail server dùng port 25 để kết nối với nhau, nên một VPS bị breach mà vẫn gửi được qua port 25 có thể phát tán spam trực tiếp đến mọi mail server nhận thư. Nhà cung cấp thường drop các packet này thay vì từ chối kết nối. Vì vậy, dấu hiệu nhận biết là kết nối treo rồi timeout, không phải một thông báo lỗi.
Hãy test từ server:
sudo apt update && sudo apt install -y netcat-openbsd
nc -vz -w 5 gmail-smtp-in.l.google.com 25
nc -vz -w 5 smtp.relay.example 587Nếu command đầu tiên chờ đủ năm giây, trong khi command thứ hai trả lời ngay, thì block đã được xác nhận. Một số nhà cung cấp sẽ gỡ block sau khi review account. Phần lớn thì không.
Block không phải lý do chính để dùng relay. Ngay cả khi port 25 được mở, mail gửi trực tiếp từ một địa chỉ VPS mới vẫn thường vào spam hoặc bị từ chối hoàn toàn. Địa chỉ đó chưa có lịch sử gửi mail và thuộc một range mà các mail server nhận thư xem là hạ tầng hosting. Hướng dẫn dành cho sender của Google yêu cầu IP gửi mail phải có forward DNS và reverse DNS hợp lệ. Nhiều địa chỉ VPS có bản ghi PTR (pointer) dạng generic mà bạn không thể thay đổi. Relay cung cấp các địa chỉ đã có lịch sử gửi mail.
Submission port là cách giải quyết vấn đề này. Port 587 dùng STARTTLS, trong đó session bắt đầu ở dạng cleartext rồi được nâng cấp lên TLS. Port 465 dùng implicit TLS (transport layer security), trong đó session được mã hóa ngay từ byte đầu tiên. Cả hai đều dành cho client đã xác thực, cả hai đều được mở trên các mạng VPS, và relay của bạn hỗ trợ ít nhất một port.
Chọn relay và subdomain gửi mail
Có nhiều nhà cung cấp mail giao dịch và họ đều thực hiện cùng một nhiệm vụ. Hãy đánh giá họ dựa trên 4 tiêu chí:
- cổng submission, 587 hoặc 465, có SMTP AUTH
- ký DKIM bằng domain và selector của bạn, không chỉ bằng thông tin của nhà cung cấp
- dữ liệu bounce và complaint có thể đọc được qua dashboard hoặc webhook
- gói dịch vụ phù hợp với volume của bạn. Tính đến tháng 8 năm 2026, một số nhà cung cấp vẫn cho phép gửi miễn phí vài nghìn message mỗi tháng. Các điều khoản này thường xuyên thay đổi, vì vậy hãy đọc trang pricing hiện tại thay vì dựa vào một bài blog
Hãy gửi mail của ứng dụng từ một subdomain. Dùng một tên như notify.example.com thay vì example.com. Các mail server nhận thư đánh giá reputation theo từng domain, vì vậy một lần gửi mail kém chất lượng từ ứng dụng sẽ không ảnh hưởng đến domain dùng cho invoice và mail của nhóm bạn. Tuy nhiên, cần hiểu rõ giới hạn này: một số mail server nhận thư tổng hợp các tín hiệu của subdomain lên domain tổ chức, vì vậy subdomain chỉ giảm mức độ ảnh hưởng chứ không cô lập hoàn toàn ảnh hưởng đó.
Cấu hình relay một lần cho mọi app tự host
Cách dễ nghĩ đến là mở trang cài đặt của từng app rồi dán SMTP host, username và password vào đó. Nextcloud, forum, Grafana, Vaultwarden và uptime monitor đều có biểu mẫu như vậy. Nếu làm thế, credential sẽ nằm ở 6 nơi, dùng 6 định dạng khác nhau, trong đó có vài nơi lưu credential bên trong database mà bạn backup như dữ liệu thay vì config. Khi đổi password, bạn sẽ cập nhật 5 nơi. Nơi thứ 6 sẽ ngừng gửi, và ngừng một cách im lặng, vì hầu hết app ghi SMTP error ở phía server nhưng vẫn hiển thị trang báo thành công cho người dùng.
Thay vào đó, hãy cấu hình relay một lần trên host và để các app gửi cục bộ. Có 2 công cụ làm tốt việc này. Lựa chọn giữa chúng phụ thuộc vào cơ chế queue.
msmtp là client tương thích với sendmail và không có daemon. Nó kết nối, gửi thư rồi thoát. Nó không có queue, nên nếu relay không thể truy cập thì message bị mất và app gọi nó nhận exit status khác 0.
Postfix được cấu hình dưới dạng satellite là một mail transfer agent đầy đủ, có queue thực sự. Nó nhận message ngay lập tức, retry trong nhiều ngày nếu gửi thất bại và lưu credential của relay trong file chỉ root có thể đọc. Hãy dùng nó khi việc mất alert trong lúc relay outage là vấn đề nghiêm trọng, hoặc khi nhiều app chạy dưới các system user khác nhau.
msmtp, lựa chọn gọn nhẹ
sudo apt update
sudo apt install -y msmtp msmtp-mta ca-certificatesmsmtp-mta cài symlink /usr/sbin/sendmail, nên mọi thứ gọi sendmail đều được chuyển đến msmtp mà không cần biết msmtp tồn tại.
Tạo /etc/msmtprc:
defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
syslog on
account relay
host smtp.relay.example
port 587
from apps@notify.example.com
set_from_header on
user <relay username>
password <relay password>
account default : relayset_from_header on luôn đặt From header và ghi đè header hiện có, nên nó thay thế giá trị app tạo bằng địa chỉ trong from. Nếu thiếu tùy chọn này, cron job sẽ gửi dưới dạng root@your-hostname, và relay từ chối vì đó không phải địa chỉ bạn đã xác minh. syslog on gửi log qua syslog, nên bạn đọc log bằng journalctl -t msmtp. Có thể dùng path logfile dùng chung, nhưng path này cần quyền ghi cho mọi user gửi mail. Đây là một cái bẫy trên máy có nhiều user.
Tự đặt permission. msmtp kiểm tra permission trên config theo từng user (~/.msmtprc), và từ chối chạy nếu config có contains secrets and therefore must have no more than user read/write permissions. Nó không kiểm tra gì trên /etc/msmtprc, vì chỉ cần file đó có thể đọc là msmtp sẽ nạp file.
sudo chown root:root /etc/msmtprc
sudo chmod 600 /etc/msmtprc
printf 'Subject: relay test\n\nsent from the host\n' | sudo sendmail -v you@example.com-v in toàn bộ SMTP conversation, nên bạn thấy từng reply từ relay. Một lần gửi thành công kết thúc bằng reply 250, cho biết relay đã chấp nhận message. Dòng authentication failed nghĩa là username hoặc password sai, hoặc relay yêu cầu API key thay cho password của account.
Đây là điểm bất tiện, cũng là lý do nhiều người chuyển sang Postfix. Với mode 600 và owner là root, chỉ root mới gửi được. App chạy dưới www-data không thể đọc file, msmtp bỏ qua file đó, và app thất bại với lỗi không tìm thấy account mặc định. Cách khắc phục là dùng group:
sudo chgrp mail /etc/msmtprc
sudo chmod 640 /etc/msmtprc
sudo usermod -aG mail www-dataNói rõ ý nghĩa của việc này: mọi member trong group mail đều có thể đọc relay password và gửi mail dưới domain của bạn từ máy đó. Trên VPS do một mình bạn quản trị, điều này có thể chấp nhận được. Nếu có nhiều app bạn không tự viết chạy dưới các user khác nhau thì không nên dùng cách này. Khi đó Postfix phù hợp hơn vì các app không bao giờ nhìn thấy credential.
Postfix dưới dạng satellite
sudo debconf-set-selections <<'EOF'
postfix postfix/main_mailer_type select Satellite system
postfix postfix/mailname string notify.example.com
postfix postfix/relayhost string [smtp.relay.example]:587
EOF
sudo DEBIAN_FRONTEND=noninteractive apt install -y postfix libsasl2-moduleslibsasl2-modules là bắt buộc. Nếu thiếu, Postfix ghi log warning: SASL authentication failure: No worthy mechs found vì các thư viện cơ chế PLAIN và LOGIN chưa được cài dưới /usr/lib/sasl2.
Thiết lập các phần còn lại bằng postconf -e. Lệnh này chỉnh sửa trực tiếp /etc/postfix/main.cf:
sudo postconf -e 'relayhost = [smtp.relay.example]:587'
sudo postconf -e 'smtp_sasl_auth_enable = yes'
sudo postconf -e 'smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd'
sudo postconf -e 'smtp_sasl_security_options = noanonymous'
sudo postconf -e 'smtp_tls_security_level = encrypt'
sudo postconf -e 'smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt'
sudo postconf -e 'inet_interfaces = loopback-only'Dấu ngoặc vuông quanh relay hostname ngăn Postfix tra cứu MX record cho hostname đó và buộc Postfix kết nối trực tiếp đến hostname. Một số relay hostname công bố MX record trỏ đến nơi khác. Nếu không có dấu ngoặc vuông, mail của bạn sẽ đi theo các record đó đến sai server.
smtp_tls_security_level = encrypt bắt buộc dùng TLS, nên message không bao giờ được gửi dưới dạng cleartext. Tùy chọn này không xác minh certificate. Tài liệu của Postfix nói rõ: ở mức đó, việc gửi vẫn tiếp tục ngay cả khi certificate của server không được tin cậy hoặc chứa sai tên. Nếu muốn kiểm tra certificate, hãy dùng verify hoặc secure và giữ smtp_tls_CAfile ở trạng thái đã bật.
Credential được lưu trong một file chỉ root có thể đọc:
echo '[smtp.relay.example]:587 relay-username:relay-password' | sudo tee /etc/postfix/sasl_passwd
sudo chmod 600 /etc/postfix/sasl_passwd
sudo postmap hash:/etc/postfix/sasl_passwd
sudo systemctl restart postfixpostmap tạo bản sao indexed mà Postfix thực sự đọc. Nếu sau đó chỉnh sửa text file nhưng quên chạy postmap, Postfix vẫn dùng database cũ và log không báo gì cho bạn biết. Trên Postfix 3.9 trở lên, map type mặc định là lmdb. Nếu muốn dùng map type đó, hãy ghi lmdb: trong cả parameter và argument postmap. Việc chỉ rõ type trên cả 2 dòng giúp chúng luôn đồng bộ.
Các app vẫn gửi mail đến root@hostname. Hãy rewrite sender:
echo '/.+/ apps@notify.example.com' | sudo tee /etc/postfix/sender_canonical
sudo postconf -e 'sender_canonical_classes = envelope_sender, header_sender'
sudo postconf -e 'sender_canonical_maps = regexp:/etc/postfix/sender_canonical'
sudo systemctl reload postfixBảng regexp: được đọc trực tiếp, nên không cần postmap. Từ giờ mọi message đều rời máy với cùng envelope sender và cùng From header, đúng với yêu cầu của relay. Đổi lại, mọi reply sẽ đổ về một nơi. Vì vậy, hãy đặt Reply-To header trong từng app để chỉ rõ người sẽ nhận reply.
Gửi thử rồi đọc log:
printf 'Subject: postfix relay test\n\nsent through the queue\n' | sendmail you@example.com
sudo tail -n 20 /var/log/mail.logMessage được gửi thành công sẽ ghi status=sent, sau đó là reply của relay trong dấu ngoặc vuông. Các trường hợp khác sẽ nêu lý do. status=deferred kèm Connection timed out nghĩa là vẫn còn thành phần trỏ đến port 25. Host or domain name not found. Name service error for name=smtp.relay.example type=A nghĩa là relay hostname sai hoặc DNS trên máy đang lỗi. mailq liệt kê các message đang bị kẹt và sudo postqueue -f retry chúng ngay.
Truy cập relay của host từ các Docker container
Một container không thể gọi sendmail của host vì binary này không có trong image và queue không được chia sẻ. Thay vào đó, hãy cung cấp cho container một network target. Postfix có thể listen trên địa chỉ của Docker bridge.
ip -4 addr show docker0
sudo postconf -e 'inet_interfaces = 127.0.0.1, 172.17.0.1'
sudo postconf -e 'mynetworks = 127.0.0.0/8 172.17.0.0/16'
sudo systemctl restart postfixHãy đọc địa chỉ bridge của chính bạn từ command đầu tiên, thay vì copy địa chỉ này, vì mỗi project Compose tạo một network trên subnet khác nhau và docker network inspect <name> sẽ in ra địa chỉ đó. Ở đây hãy dùng restart, không dùng reload: tài liệu Postfix yêu cầu phải stop rồi start sau khi thay đổi inet_interfaces, còn reload sẽ không áp dụng thay đổi này. Sau đó, mỗi app dùng SMTP host 172.17.0.1, port 25, không authentication và không TLS, vì traffic này không rời khỏi host. Nếu các service của bạn nằm trên một Compose network, chạy Docker Compose trên một VPS giải thích subnet đó được tạo từ đâu.
Đây là bước có thể gây sự cố nghiêm trọng. Postfix listen trên địa chỉ public với mynetworks quá rộng sẽ trở thành open relay: người lạ gửi mail qua relay account của bạn, provider suspend account, và reputation của domain bị ảnh hưởng trong nhiều tháng. Sau mỗi lần thay đổi, hãy kiểm tra cả hai phía.
ss -tlnp | grep ':25'Output chỉ được hiển thị địa chỉ loopback và địa chỉ bridge. Từ một máy khác, nc -vz your.server.ip 25 phải fail.
SPF, DKIM và DMARC cho domain gửi mail
Công bố cả 3 record trước khi gửi thật lần đầu. Chúng miễn phí, nằm trong DNS và là những thứ hệ thống nhận mail kiểm tra đầu tiên.
SPF (sender policy framework) liệt kê những hệ thống được phép đặt domain của bạn vào envelope sender. Công bố record này trên subdomain gửi mail:
notify.example.com. IN TXT "v=spf1 include:_spf.relay.example -all"Sao chép giá trị include: từ trang setup của relay, vì một include không resolve được sẽ gây ra lỗi vĩnh viễn thay vì pass. SPF dừng sau 10 cơ chế thực hiện truy vấn DNS và trả về permerror. Hệ thống nhận mail xem kết quả này là lỗi, vì vậy hãy giữ số lượng include ở mức thấp. Chỉ công bố đúng một record v=spf1 cho mỗi name. Có 2 record như vậy cũng là permerror.
DKIM (domainkeys identified mail) ký từng message bằng private key do relay giữ. Hệ thống nhận mail lấy public key tương ứng từ DNS. Relay sẽ cung cấp cho bạn selector và một record TXT hoặc CNAME để công bố:
sel1._domainkey.notify.example.com. IN CNAME sel1.dkim.relay.example.DKIM quan trọng hơn SPF vì DKIM vẫn hợp lệ khi message được forward. Khi mailing list hoặc một rule .forward chuyển tiếp message của bạn, message đến từ IP của hệ thống forward. Vì vậy SPF fail, còn signature vẫn verify được.
DMARC (domain-based message authentication, reporting and conformance) cho hệ thống nhận mail biết phải làm gì khi cả 2 kiểm tra đều không align, đồng thời yêu cầu hệ thống đó gửi report lại. Công bố record này trên organisational domain:
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; adkim=r; aspf=r"Bắt đầu với p=none và đọc các report trong 2 tuần. p=none không thay đổi việc delivery. Nó chỉ bật reporting, giúp bạn phát hiện những hệ thống mà bạn quên rằng vẫn đang gửi mail dưới domain của mình. Sau đó chuyển sang p=quarantine, rồi p=reject. Công bố p=reject ngay từ ngày đầu có thể khiến bạn phát hiện hệ thống invoicing đang gửi mail dưới domain này thông qua một khách hàng không bao giờ nhận được invoice.
Hãy kiểm tra những gì Internet nhìn thấy, không chỉ những gì DNS panel của bạn hiển thị:
dig +short TXT notify.example.com
dig +short TXT sel1._domainkey.notify.example.com
dig +short TXT _dmarc.example.comOutput trống nghĩa là record chưa propagate hoặc name bị sai. Một record bạn sửa 5 phút trước vẫn có thể bị cache sai trong suốt thời gian TTL (time to live) cũ của nó. Vì vậy hãy kiểm tra TTL trước khi kết luận.
Giữ From và Return-Path đồng nhất
Mỗi message có hai địa chỉ người gửi và chúng được kiểm tra theo cách khác nhau. Envelope sender được gửi trong lệnh SMTP MAIL FROM và xuất hiện trong message đã gửi dưới dạng Return-Path. Header From là địa chỉ người đọc nhìn thấy.
SPF kiểm tra domain của envelope sender với địa chỉ IP kết nối. DKIM cho biết domain đã ký, dưới dạng d=. DMARC chỉ pass khi ít nhất một trong hai domain đó align với domain trong header From. Với relaxed alignment (adkim=r, aspf=r, là mặc định), subdomain cũng được tính, nên envelope sender tại notify.example.com align với header From tại example.com. Với strict alignment thì không.
Quy tắc thực tế rất ngắn: đặt header From và envelope sender trên cùng một domain, khi đó vấn đề này không còn phát sinh. Đây chính là chức năng set_from_header on trong msmtp và sender_canonical_maps trong Postfix.
Đọc verdict trong message đã gửi. Trong Gmail, "Show original" hiển thị header do bên nhận ghi lại:
Authentication-Results: mx.google.com;
dkim=pass header.i=@notify.example.com;
spf=pass (google.com: domain of apps@notify.example.com designates 198.51.100.25 as permitted sender) smtp.mailfrom=apps@notify.example.com;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=example.comCả 3 kiểm tra đều pass ở đó. Nếu có kết quả khác, nó sẽ nêu kiểm tra nào fail và thường cho biết lý do. Đây thường là thông tin debug nhanh nhất bạn có thể lấy được về vấn đề này.
Bounce và complaint trước khi lưu lượng tăng
Bounce là khi máy chủ nhận từ chối email của bạn. Hard bounce là lỗi vĩnh viễn, và Gmail gọi trường hợp này là 550 5.1.1 The email account that you tried to reach does not exist. Soft bounce là lỗi tạm thời, mã 4xx do mailbox đầy hoặc do greylisting, rồi relay sẽ tự retry.
Relay đo hard bounce rate của bạn và đình chỉ các account liên tục gửi đến những địa chỉ không tồn tại, vì mẫu này giống một purchased list. Complaint còn quan trọng hơn. Complaint xảy ra khi người nhận bấm nút spam. Hướng dẫn dành cho sender của Google (được kiểm tra vào August 2026) yêu cầu sender giữ spam rate dưới 0.30% theo số liệu trong Postmaster Tools và khuyến nghị giữ dưới 0.10%.
Cần chuẩn bị 4 thứ trước khi lưu lượng tăng:
- một webhook hoặc lịch kiểm tra suppression list của relay hằng tuần để bạn luôn thấy được các bounce
- một địa chỉ From là mailbox thật có người đọc, với
Reply-Tođược đặt tại nơi nhận reply - yêu cầu xác nhận trước khi thêm bất kỳ địa chỉ nào vào danh sách, để bạn không bao giờ gửi đến địa chỉ mà chủ sở hữu chưa tự nhập
- rate limit cho mọi form có thể trigger việc gửi email
2 mục cuối là nơi các app self-hosted thường fail đầu tiên. Signup form không được bảo vệ cho phép bất kỳ ai nhập địa chỉ của người khác. Server của bạn gửi email xác nhận, rồi người kia đánh dấu email đó là spam. Chặn subscription bombing tại signup form là công việc về deliverability cũng như về abuse.
Không gửi bulk mail qua luồng này. Newsletter cần quản lý list và các unsubscribe header mà transactional mail không có. Vì vậy, hãy chạy newsletter qua một instance Listmonk self-hosted trên subdomain riêng, với reputation riêng. Notification mail từ một forum self-hosted nằm ở giữa: có dạng transactional nhưng lưu lượng bulk. Đây thường là loại mail đầu tiên cho bạn biết setup có hoạt động ổn định hay không.
Để tham khảo, quy định bulk sender của Gmail áp dụng khi gửi hơn 5,000 message mỗi ngày đến các địa chỉ Gmail. Quy định này yêu cầu SPF, DKIM, DMARC và one-click unsubscribe đối với marketing mail. Phần lớn app self-hosted không đạt đến ngưỡng đó. Tuy nhiên, mọi sender hiện đều được kỳ vọng phải có phần authentication.
Kiểm tra trước khi tin cậy
swaks là công cụ để làm việc này. Công cụ này nói chuyện bằng SMTP và in toàn bộ phiên trao đổi, nên bạn biết bước nào bị lỗi.
sudo apt install -y swaks
swaks --to you@example.com --from apps@notify.example.com --server smtp.relay.example --port 587 --tls --auth-user '<relay username>' --auth-password '<relay password>'Lệnh này kiểm tra thông tin xác thực trực tiếp với relay. Để kiểm tra đường đi mà các app thực sự sử dụng, hãy trỏ lệnh vào relay của host thay vào đó:
swaks --to you@example.com --from apps@notify.example.com --server 127.0.0.1Sau đó kiểm tra kết quả từ đầu đến cuối, ngay trên server, bằng email thực. Không thể chứng minh toàn bộ việc này chỉ từ các file cấu hình, vì vậy hãy tự chạy kiểm tra:
- gửi đến một dịch vụ chấm điểm như mail-tester.com. Dịch vụ này đọc SPF, DKIM, DMARC và nội dung email, rồi cho biết lý do tạo ra điểm số
- gửi đến một mailbox tại mỗi provider trong hai provider mà người dùng của bạn thực sự sử dụng, rồi đọc
Authentication-Resultstrong raw message - đưa một email qua learndmarc.com khi kết quả alignment chưa rõ ràng
- kích hoạt việc gửi email từ chính app, không chỉ từ command line, vì app là thành phần đặt header From
Có một cảnh báo cần nói rõ. Một domain hoàn toàn mới, dù cả ba record đều đúng, đôi khi vẫn bị đưa vào spam vì chưa có lịch sử. Các hệ thống nhận mail thường thận trọng với những domain mới xuất hiện từ tuần trước. Hãy bắt đầu với lưu lượng nhỏ và chỉ gửi những email mà người nhận đang chờ. Reputation sẽ được xây dựng từ đó; không có cấu hình nào bỏ qua được bước này.
FAQ
Vì sao outbound port 25 bị chặn trên VPS của tôi?
Gần như mọi nhà cung cấp đều mặc định chặn outbound TCP port 25, vì server bị breach có thể dùng port này để gửi spam trực tiếp đến mail server của bên nhận. Các packet bị drop thay vì bị từ chối, nên dấu hiệu là connection treo rồi timeout, không phải một error message. Xác nhận bằng cách chạy nc -vz -w 5 gmail-smtp-in.l.google.com 25 cạnh nc -vz -w 5 smtp.relay.example 587: lệnh đầu tiên sẽ đứng chờ, còn lệnh thứ hai trả lời ngay. Không nên yêu cầu gỡ block. Hãy gửi qua relay bằng submission port 587 hoặc 465. Hai port này thường được mở và dành cho client đã xác thực.
Tôi có cần SPF, DKIM và DMARC chỉ để gửi một vài app notification không?
Có, và volume không làm thay đổi điều đó. Mail server bên nhận áp dụng cùng một bộ kiểm tra cho một password reset như với một campaign gồm fifty thousand message. Không có SPF và DKIM, mail của bạn không được xác thực. Hướng dẫn hiện tại của Google yêu cầu mỗi sender phải có ít nhất một trong hai cơ chế này. Không có DMARC, bạn không nhận được report. Vì vậy, dấu hiệu đầu tiên của sự cố có thể là người dùng báo rằng reset link không đến nơi. Cả ba đều là DNS record, không mất phí, và việc publish chúng mất khoảng ten minutes.
Tôi nên dùng msmtp hay Postfix làm relay client?
Dùng msmtp khi một người quản trị box và việc mất message trong lúc relay outage là chấp nhận được. msmtp chỉ cần một config file và không có daemon. Vì không queue message, relay không thể truy cập đồng nghĩa với message bị mất. Dùng Postfix ở chế độ satellite khi bạn cần queue có thể retry trong nhiều ngày, hoặc khi nhiều app chạy bằng các system user khác nhau. Postfix lưu relay password trong file chỉ root đọc được, còn app không bao giờ đọc file này. Với msmtp, config phải cho mọi user gửi mail đọc được.
Vì sao mail từ app của tôi bị reject vì có sender là root?
Cron job và nhiều app tạo sender từ local user và hostname, tạo ra giá trị như root@srv1.localdomain. Đây không phải là address bạn đã verify tại relay, nên relay từ chối message bằng reply 553 hoặc 554, trong đó có tên sender address. Hãy sửa ở cấp host thay vì sửa từng app: set_from_header on cùng với address from trong /etc/msmtprc, hoặc sender_canonical_maps với sender_canonical_classes = envelope_sender, header_sender trong Postfix. Đặt Reply-To trong từng app nếu reply cần chuyển đến một người cụ thể.
Dùng subdomain riêng cho app mail có thực sự bảo vệ domain chính không?
Có, nhưng chỉ một phần, và vẫn đáng làm. Bên nhận theo dõi reputation theo từng domain, nên complaint đối với notify.example.com phần lớn vẫn nằm trong notify.example.com, trong khi domain chính tiếp tục gửi mail bình thường. Giới hạn vẫn tồn tại: một số bên nhận đưa tín hiệu của subdomain lên organisational domain, và DMARC policy publish ở organisational level sẽ áp dụng cho các subdomain nếu bạn không đặt riêng sp=. Hãy xem subdomain là biện pháp giới hạn thiệt hại, không phải sự bảo đảm.