When troubleshooting undelivered emails, we need to understand the SMTP transaction flow. A complete delivery involves these stages:
- Your SMTP server connects to recipient's MX server
- Servers exchange HELO/EHLO commands
- MAIL FROM and RCPT TO commands are executed
- DATA transmission occurs
- Transaction concludes with QUIT
Your mail server logs contain the most authoritative delivery evidence. Here's how to examine them:
# Postfix log example (typically /var/log/mail.log)
grep "unique-message-id" /var/log/mail.log
# Exim log search
exiqgrep -i message_id | exim -Mvl
Look for these key indicators:
- 250 2.0.0 Ok: Successful delivery
- 421 Service not available: Temporary failure
- 550 Mailbox unavailable: Permanent failure
The original email headers contain delivery metadata. For any sent message, you can extract headers with:
# Python example to extract headers
import email
with open('sent_email.eml', 'r') as f:
msg = email.message_from_file(f)
print(msg.items()) # Prints all headers
For direct verification without relying on logs, use these diagnostic tools:
# Telnet test to recipient's MX server
telnet mx.recipient.com 25
EHLO yourdomain.com
MAIL FROM: <sender@yourdomain.com>
RCPT TO: <recipient@theirdomain.com>
Common SMTP response codes to watch for:
Code | Meaning |
---|---|
250 | Requested action completed |
451 | Local processing error |
452 | Insufficient storage |
550 | Action not taken |
For mission-critical emails, consider implementing these techniques:
# PHP implementation of Delivery Status Notification (DSN)
$mailer = new PHPMailer();
$mailer->DSN = true;
$mailer->Debugoutput = function($str, $level) {
file_put_contents('smtp_debug.log', "$level: $str\n", FILE_APPEND);
};
Enterprise solutions include:
- SPF/DKIM/DMARC authentication logging
- Message tracking in Exchange Server
- Third-party delivery services (SendGrid, Mailgun)
When your mail server sends an email, the SMTP protocol provides several ways to track delivery status. The key components are:
- SMTP response codes (2xx, 4xx, 5xx series)
- Delivery Status Notifications (DSN)
- Message headers containing routing information
The first place to look is your mail server's logs. Here's a typical Postfix log entry for successful delivery:
Jan 1 12:34:56 mail postfix/smtp[1234]: ABC1234567: to=, relay=mx1.domain.com[1.2.3.4]:25, delay=1.2, delays=0.1/0.2/0.5/0.4, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as XYZ987)
You can manually verify if the recipient's server would accept your email:
telnet mx1.recipientdomain.com 25
HELO yourdomain.com
MAIL FROM: you@yourdomain.com
RCPT TO: recipient@recipientdomain.com
QUIT
Look for 250 response codes which indicate acceptance.
Request the recipient to provide full headers if they claim non-receipt. Key headers to examine:
- Received: (shows server hops)
- X-Received: (Gmail specific)
- Authentication-Results: (SPF/DKIM/DMARC)
For future emails, configure DSN requests in your mail server. Example for Postfix:
smtpd_discard_ehlo_keywords =
smtpd_discard_ehlo_keywords_address_maps =
default_destination_recipient_limit = 1
Here's a Python script to check delivery status using headers:
import email
import re
def check_delivery(headers):
received_headers = [h for h in headers if h.startswith('Received')]
last_server = received_headers[-1] if received_headers else None
if last_server and 'recipientdomain.com' in last_server:
return True
return False
- Recipient server greylisting
- IP reputation issues
- Strict SPF/DKIM/DMARC policies
- Mailbox storage limits
For comprehensive tracking, consider implementing a commercial email tracking solution that provides read receipts and detailed analytics.