Vì sao cần
Khi Postfix gửi mail ra ngoài bằng sai IP, SPF rất dễ fail dù bạn đã khai báo DNS tưởng như đúng. Trường hợp hay gặp là server có nhiều IPv4 hoặc IPv6, bạn thêm IP mới để gửi mail, cấu hình SPF trỏ về IP đó, nhưng Postfix vẫn dùng IP chính của máy để kết nối SMTP ra ngoài.
Kết quả là Gmail, Outlook, Yahoo hoặc hệ thống nhận mail thấy IP gửi thực tế không nằm trong bản ghi SPF. Thư có thể vào spam, bị gắn cảnh báo, hoặc bị từ chối thẳng với lỗi kiểu 550 SPF check failed.
Hai pain point phổ biến nhất:
- Bạn kiểm tra DNS thấy SPF đúng, DKIM đúng, hostname đúng, nhưng mail vẫn fail SPF.
- Bạn đổi IP gửi mail để tách reputation, nhưng log và header bên nhận lại cho thấy mail đi bằng IP khác.
Vấn đề này thường không nằm ở SPF record, mà nằm ở IP nguồn mà Postfix dùng khi mở kết nối TCP tới mail server bên nhận.
Nếu server chỉ có một IP public, bài này vẫn hữu ích để bạn biết cách đọc header và xác minh đường đi thật của email. Nếu server có nhiều IP, đây là lỗi bạn nên kiểm tra đầu tiên.
Bạn có thể đọc thêm các phần nền tảng liên quan tại tài liệu Email của VSIS hoặc trang dịch vụ hạ tầng tại https://vsis.net/.

Máy nhiều IP: Postfix mặc định dùng IP CHÍNH chứ không phải IP bạn khai
Trên một máy Linux có nhiều IP, việc bạn gán thêm IP vào card mạng không đồng nghĩa Postfix tự dùng IP đó để gửi mail. Khi Postfix tạo kết nối SMTP đi ra ngoài, kernel sẽ chọn IP nguồn dựa trên routing table, interface, policy route và cấu hình bind của ứng dụng.
Nếu bạn không cấu hình rõ, Postfix thường dùng IP chính theo tuyến mặc định. Đây thường là IP đầu tiên của server hoặc IP mà default route đang ưu tiên.
Ví dụ server có các IP:
| Vai trò | IP | Ghi chú |
|---|---|---|
| IP chính của server | 203.0.113.10 | Dùng SSH, web, default route |
| IP dự định gửi mail | 203.0.113.25 | Đã khai trong SPF |
| IPv6 chính | 2001:db8:100::10 | Có thể được ưu tiên nếu bật IPv6 |
| IPv6 gửi mail | 2001:db8:100::25 | Cần cấu hình riêng nếu muốn dùng |
Bạn khai SPF như sau:
v=spf1 ip4:203.0.113.25 -all
Nhưng Postfix lại gửi ra bằng 203.0.113.10. Bên nhận kiểm tra SPF sẽ thấy:
- Domain cho phép
203.0.113.25. - Kết nối SMTP thực tế đến từ
203.0.113.10. - IP thực tế không nằm trong SPF.
- SPF fail.
Lỗi này càng dễ xảy ra khi bạn vừa thêm IP mới cho mail, đổi nhà mạng, migrate server, hoặc dùng VPS có thêm floating IP.
Một điểm dễ nhầm nữa là myhostname, myorigin, mydestination hay PTR không quyết định IP nguồn gửi ra. Các tham số đó ảnh hưởng đến định danh mail server và domain xử lý, nhưng IP nguồn TCP vẫn cần được bind hoặc định tuyến đúng.
Bạn có thể kiểm tra nhanh cấu hình Postfix hiện tại bằng:
postconf -n
Nếu không thấy smtp_bind_address hoặc smtp_bind_address6, khả năng cao Postfix đang để hệ điều hành tự chọn IP nguồn.
Cách đọc header thư nhận được để biết IP thật đã gửi
Đừng chỉ nhìn log phía server gửi. Cách chắc nhất là gửi một thư thử tới hộp mail ngoài, sau đó mở phần header gốc của thư nhận được.
Trong Gmail, bạn mở email, bấm menu ba chấm, chọn Show original. Với Outlook, tìm mục xem View message source hoặc View message details.
Bạn cần quan tâm các dòng Received. Header email thường có nhiều dòng Received, và dòng quan trọng nhất cho SPF là dòng do mail server đầu tiên của bên nhận ghi lại.
Ví dụ:
Received: from mail.example.com (mail.example.com. [203.0.113.10])
by mx.google.com with ESMTPS id abc123
for <[email protected]>
Tue, 12 Mar 2025 10:20:30 -0700 (PDT)
Ở đây, IP thực tế kết nối tới Google là 203.0.113.10. Nếu SPF của domain chỉ có 203.0.113.25, SPF sẽ fail.
Bạn cũng có thể thấy dòng xác thực như:
Authentication-Results: mx.google.com;
spf=fail (google.com: domain of [email protected] does not designate 203.0.113.10 as permitted sender) smtp.mailfrom=example.com;
dkim=pass header.d=example.com;
dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=example.com
Dòng này cho biết rõ:
spf=fail: SPF fail.203.0.113.10: IP thực tế đã gửi.smtp.mailfrom=example.com: domain được dùng để kiểm tra SPF.dkim=pass: DKIM có thể vẫn pass, nhưng SPF fail riêng.dmarc=fail: nếu DMARC cần SPF hoặc DKIM alignment mà không đạt.
Một số hệ thống hiển thị dạng khác:
Received-SPF: Fail (protection.outlook.com: domain of example.com does not designate 203.0.113.10 as permitted sender)
Hoặc:
Received-SPF: softfail (example.com: transitioning domain does not designate 203.0.113.10 as permitted sender)
Nếu bạn dùng ~all, SPF có thể softfail thay vì fail. Nhưng bản chất vẫn là IP gửi thực tế không khớp SPF.
Cách xác định đúng dòng Received cần đọc
Header thường được thêm từ dưới lên trên. Mỗi máy trung gian thêm một dòng Received ở phía trên.
Bạn nên tìm dòng Received gần nhất với hệ thống nhận lớn như:
mx.google.comprotection.outlook.comyahoodns.net- Mail gateway của doanh nghiệp nhận
Dòng này thường chứa cụm dạng:
from hostname (hostname [IP])
by mx-receiver
IP trong dấu ngoặc vuông là IP nguồn mà bên nhận nhìn thấy.
Nếu email đi qua relay trung gian, ví dụ bạn gửi từ app vào Postfix nội bộ rồi Postfix relay qua SMTP khác, IP mà SPF kiểm tra sẽ là IP của relay cuối cùng kết nối tới MX bên nhận.
Postfix gửi mail sai IP: sửa bằng smtp_bind_address và smtp_bind_address6
Để ép Postfix gửi SMTP outbound bằng một IPv4 cụ thể, dùng tham số smtp_bind_address.
Mở file cấu hình chính:
nano /etc/postfix/main.cf
Thêm hoặc sửa:
smtp_bind_address = 203.0.113.25
Sau đó reload Postfix:
postfix reload
Hoặc:
systemctl reload postfix
Bạn có thể kiểm tra lại giá trị đang có hiệu lực:
postconf smtp_bind_address
Kết quả mong muốn:
smtp_bind_address = 203.0.113.25
Với IPv6, dùng smtp_bind_address6:
smtp_bind_address6 = 2001:db8:100::25
Reload lại:
postfix reload
Kiểm tra:
postconf smtp_bind_address6
Nếu server có cả IPv4 và IPv6, bạn cần quyết định rõ muốn gửi bằng gì. Nhiều hệ thống ưu tiên IPv6 nếu có bản ghi MX đích hỗ trợ IPv6 và Postfix được phép dùng IPv6.
Bảng so sánh các trường hợp cấu hình
| Tình huống | Cấu hình nên dùng | Rủi ro nếu bỏ qua |
|---|---|---|
| Server chỉ gửi IPv4 | smtp_bind_address = x.x.x.x | Postfix dùng IP chính, SPF fail |
| Server gửi cả IPv4 và IPv6 | smtp_bind_address và smtp_bind_address6 | IPv6 đi bằng IP không có SPF |
| Muốn tắt IPv6 cho Postfix | inet_protocols = ipv4 | Nếu không tắt, mail có thể đi IPv6 |
| Nhiều domain nhưng cùng IP gửi | Bind một IP chung | Reputation các domain dùng chung |
| Mỗi domain một IP riêng | Cần cấu hình nâng cao transport/sender dependent | Dễ nhầm IP, khó debug |
Tài liệu chính thức của Postfix có mô tả các tham số này tại Postfix postconf manual. Đây là nguồn nên đối chiếu khi bạn muốn kiểm tra ý nghĩa chính xác của từng tham số.
Nếu muốn Postfix chỉ dùng IPv4
Nếu IPv6 chưa được cấu hình DNS, PTR, SPF đầy đủ, bạn có thể tạm thời ép Postfix chỉ dùng IPv4.
Trong main.cf:
inet_protocols = ipv4
Reload Postfix:
postfix reload
Kiểm tra:
postconf inet_protocols
Lưu ý, đổi inet_protocols trong một số trường hợp nên restart thay vì chỉ reload, nhất là khi thay đổi listener hoặc môi trường đang có process cũ.
systemctl restart postfix
Không nên tắt IPv6 chỉ để né lỗi lâu dài nếu bạn thực sự cần gửi qua IPv6. Cách đúng là cấu hình IPv6 đầy đủ gồm PTR, SPF, HELO/EHLO hợp lệ và bind đúng IP.
Kiểm tra IP đã có trên server chưa
Trước khi bind, bảo đảm IP đó đang tồn tại trên máy:
ip addr
Hoặc kiểm tra nhanh:
ip addr | grep 203.0.113.25
Nếu bind vào IP không tồn tại, Postfix có thể không gửi được mail ra ngoài và log lỗi kiểu không thể bind socket.
Xem log:
tail -f /var/log/mail.log
Trên một số distro:
tail -f /var/log/maillog
Bạn có thể gặp lỗi dạng:
warning: smtp_connect_addr: bind 203.0.113.25: Cannot assign requested address
Lỗi này nghĩa là IP chưa được gán vào interface, bị sai subnet, hoặc service đang chạy trong container/network namespace không thấy IP đó.
Kiểm chứng lại bằng thư thử tới hộp ngoài
Sau khi sửa cấu hình, bạn cần gửi thư thử ra một hộp ngoài để xác nhận. Đừng chỉ tin vào postconf, vì còn có routing, NAT, firewall, container hoặc relay khác.
Bạn có thể gửi test bằng lệnh mail nếu hệ thống có sẵn:
echo "Test SPF IP bind" | mail -s "Postfix IP test" [email protected]
Hoặc dùng sendmail interface của Postfix:
sendmail [email protected]
Nhập nội dung mẫu:
Subject: Postfix IP test
This is a test.
.
Nếu dùng sendmail thủ công, kết thúc nội dung bằng dấu chấm . trên một dòng riêng tùy môi trường. Một số hệ thống cần Ctrl+D.
Sau đó mở header ở hộp nhận và kiểm tra lại:
Received: from mail.example.com (mail.example.com. [203.0.113.25])
Kỳ vọng là IP trong header đã đổi sang IP bạn bind.
Tiếp theo kiểm tra dòng xác thực:
Authentication-Results: mx.google.com;
spf=pass smtp.mailfrom=example.com;
dkim=pass header.d=example.com;
dmarc=pass header.from=example.com
Nếu SPF vẫn fail, kiểm tra theo thứ tự:
- Header có đúng IP gửi chưa.
- SPF record đã public đúng chưa.
- Domain dùng trong
MAIL FROMcó phải domain bạn sửa SPF không. - DNS đã hết cache chưa.
- Có relay trung gian nào thay IP gửi không.
Kiểm tra log Postfix khi gửi thử
Mở log khi gửi:
tail -f /var/log/mail.log
Bạn sẽ thấy các dòng tương tự:
postfix/smtp[12345]: ABCDEF123: to=<[email protected]>, relay=gmail-smtp-in.l.google.com[142.250.x.x]:25, delay=1.2, status=sent
Log này cho biết relay đích và trạng thái gửi. Nhưng nó không luôn hiển thị IP nguồn local đã dùng.
Vì vậy header bên nhận vẫn là bằng chứng quan trọng nhất.
Nếu muốn kiểm tra kết nối ở mức network, bạn có thể dùng tcpdump:
tcpdump -ni any host 142.250.x.x and port 25
Cách này cần biết IP MX đích và cần quyền root. Với server bận, dữ liệu có thể nhiều, nên chỉ dùng khi cần debug sâu.
SPF cần khớp với IP gửi thực tế
SPF không kiểm tra IP bạn nghĩ là đang gửi. SPF kiểm tra IP mà mail server nhận thấy trong kết nối SMTP.
Nếu bạn bind Postfix sang 203.0.113.25, SPF cần có IP đó:
v=spf1 ip4:203.0.113.25 -all
Nếu có cả IPv6:
v=spf1 ip4:203.0.113.25 ip6:2001:db8:100::25 -all
Nếu gửi qua một dịch vụ relay, bạn có thể cần include, ví dụ theo hướng dẫn của nhà cung cấp relay. Nhưng tránh thêm bừa quá nhiều IP hoặc include không dùng.
Bạn có thể tham khảo thêm về SPF tại RFC 7208, đây là tài liệu chuẩn mô tả cách SPF hoạt động.
Một lỗi rất thường gặp là sửa SPF cho domain hiển thị trong From, nhưng Postfix lại dùng envelope sender khác. SPF kiểm tra domain trong SMTP MAIL FROM, không nhất thiết là domain bạn nhìn thấy trong header From.
Ví dụ:
From: Brand <[email protected]>
Return-Path: <[email protected]>
Trong trường hợp này, SPF thường kiểm tra mailer.example.net, không phải example.com. DMARC mới xét alignment giữa domain hiển thị và domain xác thực.
Nếu bạn vận hành hệ thống gửi mail giao dịch, nên nắm rõ ba phần SPF, DKIM, DMARC. Bạn có thể xem thêm các tài liệu cùng cụm Email tại doc.vsis.net Email hoặc tham khảo dịch vụ máy chủ tại https://vsis.net/.
Khi nào nên tách hẳn IP gửi mail riêng
Không phải lúc nào cũng cần IP riêng cho mail. Nhưng nếu bạn gửi đều, gửi số lượng lớn, hoặc cần reputation ổn định, tách IP gửi mail là lựa chọn nên cân nhắc.
Bạn nên tách IP gửi mail riêng khi:
- Server vừa chạy web, vừa chạy mail, vừa chạy nhiều dịch vụ khác.
- Bạn muốn kiểm soát PTR/rDNS riêng cho mail.
- Bạn gửi email giao dịch quan trọng như OTP, hóa đơn, thông báo đơn hàng.
- Bạn có nhiều website hoặc app, nhưng muốn gom outbound mail qua một IP sạch.
- IP chính từng bị abuse, scan, hoặc có lịch sử blacklist.
- Bạn cần warm up IP và theo dõi reputation lâu dài.
IP gửi mail riêng nên có:
- PTR trỏ về hostname mail hợp lệ, ví dụ
mail.example.com. - A record của
mail.example.comtrỏ ngược về đúng IP. - SPF chứa đúng IP.
- DKIM ký đúng domain.
- DMARC tối thiểu
p=noneđể theo dõi. - HELO/EHLO khớp hostname có DNS hợp lệ.
Ví dụ DNS tối thiểu:
mail.example.com. A 203.0.113.25
example.com. MX 10 mail.example.com.
example.com. TXT "v=spf1 ip4:203.0.113.25 -all"
PTR cần cấu hình ở phía nhà cung cấp IP hoặc VPS, không phải trong DNS zone thông thường của domain. Nếu bạn chưa rõ cách đặt PTR, nên kiểm tra tài liệu nhà cung cấp hạ tầng hoặc liên hệ hỗ trợ.
Tách IP cũng giúp bạn debug dễ hơn. Khi header báo mail đến từ 203.0.113.25, bạn biết chắc đây là luồng mail outbound, không lẫn với traffic web hoặc service khác.
Tuy nhiên, IP riêng không tự làm mail vào inbox. Nếu IP mới hoàn toàn, bạn vẫn cần gửi tăng dần, tránh blast đột ngột, giữ bounce thấp và không gửi tới danh sách kém chất lượng.
Checklist xử lý nhanh khi SPF fail vì sai IP
Bạn có thể đi theo checklist này để tránh đoán mò:
| Bước | Việc cần làm | Lệnh hoặc nơi kiểm tra |
|---|---|---|
| 1 | Xem header thư nhận được | Show original trong Gmail |
| 2 | Tìm IP thực tế ở dòng Received | Dòng by mx.google.com hoặc gateway nhận |
| 3 | So IP với SPF hiện tại | DNS TXT của domain |
| 4 | Kiểm tra Postfix có bind IP chưa | postconf smtp_bind_address |
| 5 | Kiểm tra IPv6 | postconf smtp_bind_address6 và postconf inet_protocols |
| 6 | Reload hoặc restart Postfix | postfix reload hoặc systemctl restart postfix |
| 7 | Gửi lại thư thử | Xem lại header mới |
Nếu sau bước 7 IP vẫn sai, hãy kiểm tra thêm NAT. Trong một số môi trường cloud hoặc firewall, server bind local IP đúng nhưng outbound ra internet bị SNAT thành IP public khác.
Trường hợp dùng container cũng cần chú ý. Postfix trong container có thể không thấy IP host hoặc đi qua bridge/NAT, khiến IP public thực tế khác với IP bạn cấu hình.
Sai lầm phổ biến
Chỉ sửa SPF, không kiểm tra header
Nhiều bạn thấy SPF fail là lập tức thêm IP vào record. Cách này có thể làm SPF pass, nhưng lại che giấu việc Postfix đang gửi sai IP.
Nếu IP sai là IP chính đang dùng cho nhiều dịch vụ khác, reputation mail có thể bị ảnh hưởng. Cách đúng là xác định IP thực tế trước, rồi quyết định sửa Postfix hay sửa SPF.
Nghĩ myhostname quyết định IP gửi
myhostname chỉ là tên máy mà Postfix dùng trong nhiều ngữ cảnh, bao gồm HELO/EHLO nếu không cấu hình khác. Nó không ép kết nối SMTP outbound dùng IP tương ứng với hostname đó.
Muốn ép IP nguồn, dùng smtp_bind_address hoặc xử lý routing phù hợp.
Quên IPv6
Bạn cấu hình IPv4 rất chuẩn nhưng server vẫn có IPv6. Postfix có thể gửi tới MX hỗ trợ IPv6 và SPF lại fail vì thiếu ip6.
Nếu chưa sẵn sàng cho IPv6, đặt:
inet_protocols = ipv4
Nếu dùng IPv6, cấu hình đầy đủ smtp_bind_address6, PTR IPv6 và SPF ip6.
Bind vào IP chưa gán trên server
Cấu hình trong main.cf không tự tạo IP trên hệ điều hành. IP phải tồn tại trên interface hoặc trong network namespace mà Postfix đang chạy.
Luôn kiểm tra bằng:
ip addr
Không reload Postfix sau khi sửa
Sửa main.cf xong nhưng quên reload là lỗi rất cơ bản. Sau khi sửa, chạy:
postfix check
postfix reload
Nếu thay đổi liên quan inet_protocols, bạn có thể restart:
systemctl restart postfix
Kiểm tra nhầm domain SPF
SPF kiểm tra envelope sender, thường thấy ở Return-Path, không phải lúc nào cũng là domain trong From.
Nếu app gửi mail với bounce domain riêng, bạn phải sửa SPF cho bounce domain đó.
Key takeaways
- Postfix gửi mail trên máy nhiều IP thường dùng IP theo routing mặc định nếu bạn không bind rõ.
- SPF fail xảy ra khi IP thực tế kết nối tới MX bên nhận không nằm trong SPF của envelope sender.
- Header thư nhận được là nguồn kiểm chứng đáng tin nhất để biết IP thật đã gửi.
- Dùng
smtp_bind_addresscho IPv4 vàsmtp_bind_address6cho IPv6. - Nếu chưa cấu hình IPv6 đầy đủ, cân nhắc
inet_protocols = ipv4. - Sau khi sửa, luôn gửi thư thử tới Gmail hoặc Outlook và xem lại
Authentication-Results. - IP gửi mail riêng giúp kiểm soát reputation, PTR, SPF và debug dễ hơn.
Câu hỏi thường gặp
Vì sao SPF fail dù tôi đã thêm đúng IP vào DNS?
Có thể IP bạn thêm không phải IP Postfix đang dùng để gửi ra ngoài. Hãy mở header thư nhận được và kiểm tra dòng Received do MX bên nhận ghi.
Cũng cần kiểm tra domain SPF có đúng với envelope sender không. SPF thường dựa vào Return-Path hoặc SMTP MAIL FROM.
smtp_bind_address có ảnh hưởng mail inbound không?
Không. smtp_bind_address dùng cho SMTP client của Postfix khi gửi mail ra ngoài.
Mail inbound phụ thuộc vào listener trong master.cf, inet_interfaces, firewall, DNS MX và các cấu hình nhận mail khác.
Tôi có cần thêm cả IP chính và IP mail vào SPF không?
Nếu cả hai IP đều thực sự gửi mail hợp lệ cho domain đó, bạn có thể thêm cả hai. Nhưng nếu mục tiêu là chỉ gửi bằng IP mail riêng, nên sửa Postfix để dùng đúng IP thay vì cho phép cả IP sai.
SPF càng rộng thì bề mặt rủi ro càng lớn. Chỉ đưa vào các nguồn gửi thật sự cần thiết.
Vì sao Gmail vẫn báo fail sau khi tôi sửa SPF?
DNS có thể còn cache, hoặc thư mới vẫn đi bằng IP cũ. Hãy gửi thư test mới, không kiểm tra lại thư cũ.
Bạn cũng nên kiểm tra bằng header, vì Gmail sẽ ghi rõ IP nào không được SPF cho phép.
Có nên dùng ~all thay vì -all để tránh fail không?
~all làm SPF softfail, thường đỡ bị từ chối hơn trong giai đoạn chuyển đổi. Nhưng nó không sửa nguyên nhân gốc nếu Postfix đang gửi sai IP.
Khi hệ thống đã ổn định, nhiều domain nên dùng chính sách chặt hơn tùy nhu cầu và mức tự tin.
Một server có thể gửi mỗi domain bằng một IP khác nhau không?
Có, nhưng cấu hình phức tạp hơn. Bạn cần sender-dependent transport, nhiều instance Postfix, policy routing, hoặc kiến trúc relay riêng.
Nếu chỉ có một vài domain và một IP gửi chung là đủ, nên giữ cấu hình đơn giản để dễ vận hành.
Tóm tắt nhanh
- SPF fail thường do IP gửi thực tế khác IP bạn khai trong DNS.
- Kiểm tra header thư nhận được để thấy IP thật trong dòng
Received. - Cấu hình
smtp_bind_addressđể ép Postfix gửi IPv4 bằng IP mong muốn. - Cấu hình
smtp_bind_address6hoặc tắt IPv6 bằnginet_protocols = ipv4nếu cần. - Luôn reload hoặc restart Postfix sau khi sửa
main.cf. - Gửi thư thử tới hộp ngoài và xem
Authentication-Resultsđể xác nhận SPF pass. - Với hệ thống gửi mail nghiêm túc, nên tách IP gửi mail riêng và cấu hình PTR, SPF, DKIM, DMARC đầy đủ.



