Skip to main content

5. Address Resolution and Mail Handling

This section describes how SMTP clients determine where to deliver mail messages and how they should handle the delivery process.

5.1. Locating the Target Host

When an SMTP client has mail to deliver to a particular domain, it must determine the appropriate destination host(s). This process uses the Domain Name System (DNS) and follows these steps:

Step 1: Look up MX Records

Query DNS for Mail eXchanger (MX) records for the destination domain:

$ dig example.com MX

;; ANSWER SECTION:
example.com. 3600 IN MX 10 mail1.example.com.
example.com. 3600 IN MX 20 mail2.example.com.
example.com. 3600 IN MX 30 mail3.example.com.

Step 2: Sort by Priority

Sort MX records by priority (lower number = higher priority):

  1. mail1.example.com (priority 10)
  2. mail2.example.com (priority 20)
  3. mail3.example.com (priority 30)

Step 3: Attempt Delivery

Try to connect to each host in priority order:

  1. Attempt connection to highest priority (lowest number) MX
  2. If connection fails, try next priority level
  3. Continue until successful or all MX hosts exhausted

Step 4: Fallback to A/AAAA Records

If no MX records exist, treat the domain itself as the mail server:

  • Look up A record (IPv4) or AAAA record (IPv6)
  • Attempt direct connection to that IP address

Important: If MX records exist but all fail, do NOT fall back to A/AAAA records.

Detailed Algorithm

1. Query MX records for destination domain
2. If MX records found:
a. Remove any MX pointing to "." (null MX)
b. Sort remaining MX by priority
c. For each priority level (starting with lowest number):
i. Resolve all MX hosts at this priority to IP addresses
ii. Randomly order hosts at same priority
iii. Try connecting to each host
iv. If connection succeeds, deliver mail
v. If all hosts at this priority fail, try next priority
d. If all MX hosts fail, defer delivery (temporary failure)
3. If no MX records found:
a. Query A/AAAA records for domain
b. Try connecting directly to domain's IP
c. If connection fails, defer delivery
4. If domain does not resolve:
- Return permanent failure (5xx code)

Example Scenarios

Scenario 1: Standard MX Resolution

Domain: example.com

MX Records:
10 mail1.example.com
20 mail2.example.com

Process:
1. Try mail1.example.com → Success, deliver mail

Scenario 2: Primary MX Fails

MX Records:
10 mail1.example.com (down)
20 mail2.example.com

Process:
1. Try mail1.example.com → Connection failed
2. Try mail2.example.com → Success, deliver mail

Scenario 3: No MX Records

Domain: smallcompany.example

No MX records found

Process:
1. Look up A record for smallcompany.example
2. Connect directly to IP address
3. Deliver mail

Scenario 4: Null MX Record

Domain: nomail.example

MX Record:
0 .

Meaning: This domain does not accept mail
Process: Return permanent failure (556 or 550)

Best Practices

  1. Respect TTL: Cache DNS results according to TTL values
  2. Connection Timeouts: Use reasonable timeouts (e.g., 5 minutes for initial connection)
  3. Retry Logic: For transient failures (4xx), retry periodically
  4. Load Balancing: For same-priority MX records, randomize selection
  5. IPv6 Support: Try both A and AAAA records
  6. Error Handling: Distinguish between temporary and permanent failures

Common Errors

Error 1: Falling back to A record when MX exists but fails

❌ Wrong:
MX records exist but all fail → Try A record

✅ Correct:
MX records exist but all fail → Defer delivery (temporary failure)

Error 2: Not handling null MX properly

❌ Wrong:
MX: 0 . → Ignore and try A record

✅ Correct:
MX: 0 . → Domain explicitly rejects mail, return permanent error

5.2. IPv6 and MX Records

When resolving MX hostnames, clients should:

  1. Query both A (IPv4) and AAAA (IPv6) records
  2. Prefer IPv6 if both available (implementation-dependent)
  3. Fall back to IPv4 if IPv6 connection fails

Example:

mail.example.com has:
A 192.0.2.1
AAAA 2001:db8::1

Process:
1. Try IPv6: 2001:db8::1
2. If fails, try IPv4: 192.0.2.1

IPv6 Address Literals

SMTP supports IPv6 address literals in MAIL FROM and RCPT TO:

Format: user@[IPv6:2001:db8::1]

Example:

C: MAIL FROM:`<sender@[IPv6:2001:db8::1]>`
S: 250 Ok

Dual-Stack Considerations

  1. Happy Eyeballs: Try IPv6 and IPv4 in parallel with slight delay
  2. Timeout Handling: Don't let IPv6 attempts delay IPv4 too long
  3. Preference: Allow configuration of IPv4/IPv6 preference
  4. Fallback: Always have IPv4 fallback for compatibility