LFCE 65 ๐ง Mail Server โ Sending and Receiving
The previous two chapters configured Postfix to move mail and Dovecot to serve it. This chapter covers the end-to-end flow: what happens when a local user sends a message, how Postfix determines whether to deliver it locally or relay it to a remote server, the difference between the SMTP submission port and the SMTP transport port, and the diagnostic tools that show where a message is stuck. The configuration from the previous chapters is assumed to be in place; this chapter exercises it.
A mail system has two directions. Inbound mail arrives from remote servers on port 25, is accepted by Postfix, and is delivered to a local mailbox or forwarded to a Dovecot LMTP socket. Outbound mail is submitted by a local user or an authenticated client, is queued by Postfix, and is relayed to the destination server using DNS MX lookups. The two directions use different ports, different authentication requirements, and different Postfix components.
Key point: Port 25 is the SMTP transport port. It accepts mail from other mail servers, and it must be reachable from the internet for inbound mail to work. Port 587 is the SMTP submission port. It requires authentication and is used by mail clients to send mail through the server. Postfix does not enable port 587 by default; it must be configured with a master.cf entry and an authentication mechanism. The two ports look similar but serve different purposes, and conflating them is the most common source of “cannot send mail” problems.
Why inbound and outbound mail require different configurations
The port-separation problem.
Port 25 is for server-to-server transport. Remote mail servers connect to it to deliver mail for the domains in mydestination. The connection is not authenticated; the server is identified by its IP address and hostname, and the trust is established by DNS and, increasingly, by SPF, DKIM, and DMARC. Port 587 is for client submission. The client authenticates with a username and password, and Postfix accepts the mail for relay to any destination. A client that connects to port 25 and tries to relay to an external address receives a “Relay access denied” error because port 25 is not an authenticated submission port .
The DNS MX problem.
When Postfix has a message for user@remote.com, it queries DNS for the MX record of remote.com. The MX record lists the mail servers that accept mail for the domain, ordered by priority. Postfix connects to the highest-priority server and delivers the message. If the MX lookup fails or the servers are unreachable, the message is deferred and retried according to the maximal_queue_lifetime setting, which defaults to five days . A message that cannot be delivered within that window is bounced to the sender.
The local-delivery problem.
When Postfix has a message for a domain in mydestination, it does not query DNS. It delivers the message to the local mailbox using the local delivery agent or forwards it to Dovecot using the lmtp transport. The mailbox_transport parameter in main.cf selects the delivery method. Without it, Postfix writes to /var/mail/$USER in mbox format, which is not what Dovecot is configured to read if the mailbox format is Maildir .
a. Sending mail from the command line
The mail or mailx command submits a message to the local Postfix instance. Postfix queues it and delivers it according to the recipient’s domain.
# Send a simple message to a local user
echo "Test body" | mail -s "Test subject" root
# Send to a remote address
echo "Test body" | mail -s "Test subject" user@remote.com
# Send with an attachment (mailx)
echo "Body" | mailx -s "Subject" -a /path/to/file.pdf user@remote.com
# Check the queue
mailq
# Check the log
sudo tail -f /var/log/mail.log # Debian
sudo tail -f /var/log/maillog # RHEL
The mail command reads the body from stdin and the subject from the -s flag. The message is passed to the local Postfix instance over the sendmail compatibility interface, which is a Unix socket at /var/spool/postfix/public/sendmail. Postfix queues the message and returns immediately; the delivery happens asynchronously . The mailq command shows the queue, and the log shows the delivery status.
The log entry for a successful delivery includes status=sent and the relay. For a deferred message, it includes status=deferred and the reason, such as Connection timed out or Host or domain name not found.
# Find the log entries for a specific recipient
grep "user@remote.com" /var/log/mail.log
b. Configuring the submission port
Port 587 requires a master.cf entry and an authentication mechanism. The submission service is defined in master.cf with the smtpd command and the submission profile.
# /etc/postfix/master.cf
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
The submission service listens on port 587. The smtpd_tls_security_level=encrypt requires TLS on the connection, which protects the credentials. The smtpd_sasl_auth_enable=yes enables SASL authentication. The smtpd_client_restrictions and smtpd_recipient_restrictions deny clients that are not authenticated . The permit_sasl_authenticated directive is the key: it allows authenticated clients to relay to any destination, while rejecting unauthenticated clients.
The SASL authentication is provided by Dovecot. Postfix delegates the authentication to Dovecot’s SASL socket, which is configured in main.cf.
# /etc/postfix/main.cf
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_tls_security_level = may
smtpd_tls_cert_file = /etc/postfix/ssl/fullchain.pem
smtpd_tls_key_file = /etc/postfix/ssl/privkey.pem
The smtpd_sasl_type = dovecot tells Postfix to use Dovecot’s SASL implementation. The smtpd_sasl_path = private/auth is the relative path to the socket under the Postfix queue directory. The smtpd_tls_security_level = may allows TLS but does not require it on port 25; the submission port overrides this with encrypt . Dovecot must be configured to provide the SASL socket, which is covered in the next section.
c. The Dovecot SASL socket and LMTP delivery
Dovecot provides two services to Postfix: the SASL authentication socket for submission, and the LMTP socket for local delivery. Both are configured in Dovecot’s 10-master.conf.
# /etc/dovecot/conf.d/10-master.conf
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
The auth service creates a Unix socket at /var/spool/postfix/private/auth, which is the path that smtpd_sasl_path = private/auth refers to. The socket is owned by the postfix user so that Postfix can connect to it . The lmtp service creates a second socket at /var/spool/postfix/private/dovecot-lmtp, which Postfix uses to deliver mail to Dovecot.
The Postfix side of the LMTP delivery is configured in main.cf with the mailbox_transport parameter.
# /etc/postfix/main.cf
mailbox_transport = lmtp:unix:private/dovecot-lmtp
virtual_transport = lmtp:unix:private/dovecot-lmtp
The mailbox_transport parameter applies to the domains in mydestination, and the virtual_transport applies to the domains in virtual_mailbox_domains. Both point to the same LMTP socket. When Postfix has a message for a local user, it hands the message to Dovecot over LMTP, and Dovecot writes it to the user’s Maildir . This is the integration that makes the mail readable over IMAP.
Complete Example Session
# ============================================
# PART 1: CONFIGURE THE SUBMISSION PORT
# ============================================
sudo tee -a /etc/postfix/master.cf > /dev/null <<'EOF'
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
EOF
# ============================================
# PART 2: CONFIGURE SASL IN POSTFIX
# ============================================
sudo tee -a /etc/postfix/main.cf > /dev/null <<'EOF'
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_tls_security_level = may
EOF
# ============================================
# PART 3: CONFIGURE DOVECOT SASL AND LMTP
# ============================================
sudo tee -a /etc/dovecot/conf.d/10-master.conf > /dev/null <<'EOF'
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
EOF
# ============================================
# PART 4: CONFIGURE LMTP DELIVERY IN POSTFIX
# ============================================
sudo tee -a /etc/postfix/main.cf > /dev/null <<'EOF'
mailbox_transport = lmtp:unix:private/dovecot-lmtp
virtual_transport = lmtp:unix:private/dovecot-lmtp
EOF
# ============================================
# PART 5: RESTART BOTH SERVICES
# ============================================
sudo systemctl restart dovecot
sudo systemctl restart postfix
# ============================================
# PART 6: VERIFY THE PORTS
# ============================================
sudo ss -tlnp | grep -E ":25|:587|:143"
# Output: 25 (SMTP), 587 (submission), 143 (IMAP)
# ============================================
# PART 7: TEST LOCAL DELIVERY
# ============================================
echo "Local test" | mail -s "Local test" test
# The message is delivered to /home/vmail/test/Maildir/new/
# ============================================
# PART 8: CHECK THE MAILBOX
# ============================================
ls -la /home/vmail/test/Maildir/new/
# Output shows the new message file
# ============================================
# PART 9: TEST SUBMISSION AUTHENTICATION
# ============================================
# Using swaks or openssl s_client to test the submission port
openssl s_client -connect localhost:587 -starttls smtp
# EHLO localhost
# AUTH PLAIN <base64-credentials>
# MAIL FROM:<test@example.com>
# RCPT TO:<user@remote.com>
# DATA
# Subject: Test
#
# Body
# .
# QUIT
# ============================================
# PART 10: CHECK THE LOG
# ============================================
sudo tail -10 /var/log/mail.log
# Output shows the delivery status for the local message
The ten parts demonstrate the complete sending and receiving flow: the submission port configuration, the SASL settings, the Dovecot SASL and LMTP sockets, the LMTP delivery, the service restarts, the port verification, the local delivery test, the mailbox inspection, the submission authentication test, and the log check. The critical verification is Parts 7 and 8: a local message is delivered to the Maildir, which confirms that the LMTP integration is working.
Quick Reference
SMTP Ports
| Port | Purpose | Authentication |
|---|---|---|
| 25 | Server-to-server transport | No (uses DNS and reputation) |
| 587 | Client submission | Yes (SASL) |
| 465 | Implicit TLS submission | Yes (SASL) |
| 143 | IMAP | Yes (login) |
| 993 | IMAPS | Yes (login over TLS) |
Postfix Submission Settings
| Setting | Purpose |
|---|---|
smtpd_sasl_auth_enable = yes | Enable SASL |
smtpd_sasl_type = dovecot | Use Dovecot’s SASL |
smtpd_sasl_path = private/auth | Socket path |
smtpd_tls_security_level = encrypt | Require TLS on submission |
permit_sasl_authenticated,reject | Allow authenticated, reject others |
Delivery Transports
| Setting | Purpose |
|---|---|
mailbox_transport | Delivery for mydestination |
virtual_transport | Delivery for virtual domains |
lmtp:unix:private/dovecot-lmtp | Dovecot LMTP socket |
Diagnostic Commands
| Command | Purpose |
|---|---|
mailq | Show the queue |
postqueue -f | Flush the queue |
tail -f /var/log/mail.log | Follow the mail log |
grep <recipient> /var/log/mail.log | Find a message’s status |
openssl s_client -connect :587 -starttls smtp | Test submission |
Best Practices
โ Do This:
# Enable the submission port with SASL and TLS
submission inet n - y - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes # โ
# Use Dovecot for SASL authentication
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth # โ
# Deliver local mail via LMTP to Dovecot
mailbox_transport = lmtp:unix:private/dovecot-lmtp # โ
# Check the log after sending a test message
tail -f /var/log/mail.log # โ
# Flush the queue after fixing a relay issue
postqueue -f # โ
โ Don’t Do This:
# Allow unauthenticated relay on port 25
smtpd_recipient_restrictions = permit_mynetworks, permit # โ
# Use port 25 for client submission
# Clients receive "Relay access denied" # โ
# Skip TLS on the submission port
smtpd_tls_security_level = none # Credentials in cleartext # โ
# Forget to restart Dovecot after changing its sockets
# The SASL socket is not created # โ
# Ignore deferred messages
# The queue grows and disk fills # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Relay access denied | Client not authenticated on port 25 | Use port 587 with SASL |
| Cannot connect to submission port | master.cf entry missing | Add the submission service |
| Authentication fails | Dovecot SASL socket not created | Restart Dovecot; check permissions |
| Local mail not in Maildir | No mailbox_transport | Set it to the LMTP socket |
| Messages deferred | DNS or destination server issue | Check the log; postqueue -f |
| Port 587 not listening | Postfix not reloaded | postfix reload |
Real-World Examples
1. Send a local message
echo "Body" | mail -s "Subject" root
2. Send a remote message
echo "Body" | mail -s "Subject" user@remote.com
3. Check the queue
mailq
4. Follow the log
tail -f /var/log/mail.log
5. Find a message’s status
grep "user@remote.com" /var/log/mail.log
6. Enable submission
submission inet n - y - - smtpd
7. SASL configuration
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
8. LMTP delivery
mailbox_transport = lmtp:unix:private/dovecot-lmtp
9. Test submission
openssl s_client -connect localhost:587 -starttls smtp
10. Flush the queue
postqueue -f
Visual
Inbound and Outbound Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TWO DIRECTIONS, TWO PORTS โ
โ โ
โ INBOUND (port 25): โ
โ Remote server โโโถ Postfix:25 โโโถ LMTP โโโถ Dovecot โโโถ Maildirโ
โ โ
โ OUTBOUND (port 587): โ
โ Mail client โโโถ Postfix:587 (SASL) โโโถ Queue โโโถ MX lookup โ
โ โโโโถ Remote server:25 โ
โ โ
โ LOCAL DELIVERY: โ
โ Local user โโโถ Postfix (sendmail) โโโถ LMTP โโโถ Dovecot โ
โ โ
โ Port 25 is unauthenticated transport. โ
โ Port 587 is authenticated submission. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Postfix-Dovecot Integration
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ TWO SOCKETS CONNECT POSTFIX AND DOVECOT โ
โ โ
โ /var/spool/postfix/private/auth โ
โ โโโ Created by Dovecot's `service auth` โ
โ โโโ Used by Postfix for SASL authentication โ
โ โโโ Referenced by `smtpd_sasl_path = private/auth` โ
โ โ
โ /var/spool/postfix/private/dovecot-lmtp โ
โ โโโ Created by Dovecot's `service lmtp` โ
โ โโโ Used by Postfix for local delivery โ
โ โโโ Referenced by `mailbox_transport` โ
โ โ
โ Both sockets are owned by the postfix user. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Message Lifecycle
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ FROM SUBMISSION TO DELIVERY โ
โ โ
โ 1. Client submits to port 587 with SASL โ
โ 2. Postfix authenticates via Dovecot SASL socket โ
โ 3. Postfix queues the message โ
โ 4. Postfix looks up MX for the recipient's domain โ
โ 5. Postfix connects to the destination on port 25 โ
โ 6. Destination server accepts or rejects โ
โ โโโ Accept โ status=sent โ
โ โโโ Reject โ status=deferred or bounced โ
โ โ
โ Local delivery bypasses steps 4-6 and uses LMTP. โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Inbound port | 25 (SMTP transport) |
| Submission port | 587 (authenticated) |
| Implicit TLS port | 465 (submissions) |
| SASL provider | Dovecot |
| SASL socket | /var/spool/postfix/private/auth |
| LMTP socket | /var/spool/postfix/private/dovecot-lmtp |
| Local transport | mailbox_transport |
| Virtual transport | virtual_transport |
| Queue view | mailq |
| Log (Debian) | /var/log/mail.log |
| Log (RHEL) | /var/log/maillog |
| Flush queue | postqueue -f |
Key takeaways:
- Port 25 and port 587 serve different purposes. Port 25 is for server-to-server transport and is not authenticated. Port 587 is for client submission and requires SASL authentication. A client that connects to port 25 and tries to relay receives “Relay access denied” .
- Postfix delegates authentication and delivery to Dovecot. The SASL socket at
private/authhandles authentication, and the LMTP socket atprivate/dovecot-lmtphandles local delivery. Both sockets are created by Dovecot and owned by the postfix user . - The
mailbox_transportparameter routes local mail to Dovecot. Without it, Postfix writes to/var/mail/$USERin mbox format, which Dovecot is not configured to read if the mailbox format is Maildir. - The MX lookup determines the outbound destination. Postfix queries DNS for the recipient’s MX record and connects to the highest-priority server. A failed lookup or unreachable server causes the message to be deferred and retried according to
maximal_queue_lifetime. - The log is the diagnostic center. A successful delivery shows
status=sent, a temporary failure showsstatus=deferredwith a reason, and a permanent failure showsstatus=bounced. The queue and the log together show where a message is stuck. postqueue -fretries all deferred messages. After fixing a relay or DNS issue, the flush command retries the queued messages immediately instead of waiting for the next retry interval.
Remember: Sending and receiving are two flows through the same Postfix instance. Inbound mail arrives on port 25 and is delivered to Dovecot over LMTP. Outbound mail is submitted on port 587 with SASL authentication and relayed to the destination’s MX. Local mail takes the same LMTP path as inbound. The SASL and LMTP sockets are the integration points, and the log is the tool that shows what happened. Configure the submission port, enable SASL, set the LMTP transport, restart both services, send a test message, and check the log.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!