baseline_mailrelay¶
The cake function baseline_mailrelay
executes the Ansible role-mailrelay-opensmtpd, which installs and configures opensmtpd to relay emails generated by (Web) applications to authenticated SMTP-Servers (like gmail).
It can also relay emails to the matrix chat.
Simplified, the opensmtpd-mailrelay works as follows:
- Opensmtpd uses
action
andmatch
directives in/etc/smtpd.conf
to handle mail generated by Webapps, Cronjobs and so on - The mails are sorted by the "MAIL FROM" header (set by the Mail User Agent) using the
match
directive, which associates the email with anaction
- The
action
defines over which external relay server (for example gmail.com) to relay the mail
Information¶
Key | Value |
---|---|
Playbook path | plays/baseline/mailrelay.yml |
Role | https://git.blunix.com/ansible-roles/role-mailrelay-opensmtpd |
Tags | https://git.blunix.com/ansible-roles/role-mailrelay-opensmtpd/-/tags |
Defaults | https://git.blunix.com/ansible-roles/role-mailrelay-opensmtpd/-/blob/master/defaults/main.yml |
Config file | Description |
---|---|
/etc/mailname | Contains the hostname the server should use during SMTP connections as well as writing into the email headers |
/etc/smtpd.conf | Main config file |
/etc/smtpd/ | Main config directory |
/etc/smtpd/tables | Directory for database-like files, like smtp-user and -password information |
/etc/smtpd/tables/monitoring_{from,recipients} | Contains database of email addresses to relay to monitoring (matrix chat) |
/etc/smtpd/tables/relay_secrets | Contains relay host authentication data (gmail.com login) |
/etc/smtpd/filters | Directory for scripts that scan and modify or accept / reject email |
/etc/smtp-to-matrix/config.yml | Contains matrix chat authentication data |
Example¶
passwords:
pass edit mailrelay_smtp_to_matrix_username
pass edit mailrelay_smtp_to_matrix_password
compile-passwords.py
inventory/group_vars/all.yml
:
# role-mailrelay-opensmtpd
# Hostname for this mailrelay - should not be the servers actual hostname
# Commonly just the domain of the company running the server
# Will be written into the header of all outgoing emails
# Has to be an existing mailserver with a MX record
mailrelay_opensmtpd_mailname: mail.example.com
#mailrelay_smtp_to_matrix_username: from password store
#mailrelay_smtp_to_matrix_password: from password store
mailrelay_smtp_to_matrix_server: "https://matrix.org"
mailrelay_smtp_to_matrix_room_id: "!matrix-monitoring-room-id-here:matrix.org"
inventory/group_vars/util_backup.yml
:
mailrelay_opensmtpd_monitoring_linux_users:
- root
- borgbackup
inventory/group_vars/cus_www_prod_web.yml
:
mailrelay_opensmtpd_relays:
# Alias for this relay
- alias: myrelay
# Relay server DNS name or IP
server: "mail.example.com"
# mail-from email address
mail-from: monitoring@example.com
# Relay server protocol (Documentation: https://man.openbsd.org/smtpd.conf#host)
protocol: "smtp+tls"
# Enforce TLS (default: True)
tls: True
# Do not verify TLS certificates (default: False)
tls: True
# Relay server port
port: "587"
# Relay server SMTP login
login: opensmtpd@example.com
# Relay server SMTP password
# This should be in the password-store!
password: "{{ cus_www_prod_web_email_password }}"
# Linux of sender addresses to apply this relay for
from:
- root
- www-data
- opensmtpd@example.com
# Simple version
- alias: backup
server: "mail.beispiel.de"
protocol: "smtps"
tls: True
port: "465"
login: backup@beispiel.de
password: superduperhyperextremelysecret
from:
- backuppc
Usage¶
Password for encrypted mails in queue¶
The opensmtpd mail queue is encrypted. To interact with it, you need to enter a password. This password is in ansible-cake
in the password store:
CAKE master pass show mailrelay_opensmtpd_conf_queue_encryption
otalR1o1RdygQ7Az12N53e1ytrjk7pee
CAKE master cake ssh web-2 root pub
root@cus-www-prod-web-2 ~ # smtpctl show message pmRXuDvpF4892vik
key> <ENTER mailrelay_opensmtpd_conf_queue_encryption PASSWORD HERE>
root@cus-www-prod-web-2 ~ # smtpctl show envelope pmRXuDvpF4892vik
Common commands¶
Show mails in queue
smtpctl show queue
Show number of mails in queue
smtpctl show queue | nl # Few mails
smtpctl show queue | wc -l # Lots of mails
Show size of mail queue directory
du -sh /var/spool/smtpd/
Delete specific mail(s) in the queue
smtpctl show queue
smtpctl remove <queue-id> <que-id>
Delete all mails in the queue
smtpctl remove all
Show a specific emails body
smtpctl show <queue-id>
smtpctl show message a2c25ab9d701c1c6
Show a specific emails envelope
smtpctl show <queue-id>
smtpctl show envelope a2c25ab9d701c1c6
Re-attempt delivery of all mails in the queue
smtpctl schedule all
Debugging while sending¶
To debug the path an email takes on the system, use the following commands:
Sending a test email, setting MAIL FROM to "root":
root@server ~ # echo testbody | mail -s testsubject recipient@example.com
Sending a test email, setting MAIL FROM to "grafana":
root@server ~ # echo fo | mail -s testsubject -a "From: grafana" recipient@example.com
Sending a test email, setting MAIL FROM to a user not defined in any "match" statement:
root@server ~ # echo fo | mail -s testsubject -a "From: nonexistinguser" recipient@example.com
mail: cannot send message: Process exited with a non-zero status
Showing the email in the mail queue:
smtpctl show queue
3ac1dk9c0f839114|local|mta|auth|grafana@mailhost.cus.int|recipient@example.com|recipient@example.com|1844442211|1844442211|1644441235|0|inflight|0|
/var/log/mail.log¶
Logs for a successfully relayed email. The most important part is the stat="250 Ok
at the end, which is the answer of the relaying mailserver (gmail.com in this example) saying: Ok, I have taken this email and will relay it accordingly.
tail -n 0 -f /var/log/mail.log
# Now send the email and watch the logs
smtp connected address=local host=mail.example.com
smtp message msgid=d994c46d size=464 nrcpt=1 proto=ESMTP
smtp envelope evpid=d994c46d2502c97b from=<grafana@mailhost.cus.int> to=<recipient@example.com>
smtp disconnected reason=quit
mta connecting address=smtp+tls://1.2.3.4:587 host=gmail.com
mta connected
mta tls ciphers=TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256
mta server-cert-check result="success"
mta delivery evpid=d994c46d2502c97b from=<monitoring@example.com> to=<recipient@example.com> rcpt=<-> source="3.4.5.6" relay="1.2.3.4 (gmail.com)" delay=1s result="Ok" stat="250 Ok 0107017ee057c78c-d9f1e0e9-a73b-48e0-bb5b-430640e0edd7-000000"
Logs for an invalid MAIL FROM. Note that opensmtpd complains about the RCTP TO, even though the MAIL FROM is the problem, as there is no match defined for this MAIL FROM:
smtp connected address=local host=mail.example.com
smtp failed-command command="RCPT TO:<recipient@example.com> " result="550 Invalid recipient: <recipient@example.com>
smtp disconnected reason=disconnect
Logs for an unreachable relay-server. In this case the local firewall blocks the connection (connection refused):
smtp connected address=local host=mail.example.com
smtp message msgid=07ecd737 size=464 nrcpt=1 proto=ESMTP
smtp envelope evpid=07ecd737503da7ae from=<grafana@mailhost.cus.int> to=<recipient@example.com>
smtp disconnected reason=quit
mta connecting address=smtp+tls://1.2.3.4:587 host=gmail.com
mta error reason=IO Error: Connection refused
smtp-out: Disabling route [] <-> 1.2.3.4 (gmail.com) for 15s
Logs for a mailserver relay that has a bad SSL certificate (sadly very common):
smtp connected address=local host=mail.example.com
smtp message msgid=8d2b2bfd size=518 nrcpt=1 proto=ESMTP
smtp envelope evpid=8d2b2bfd60715eac from=<monitoring@example.com> to=<recipient@example.com>
mta connecting address=smtp+tls://1.2.3.4:587 host=gmail.com
smtp disconnected reason=quit
mta connected
mta tls ciphers=TLSv1.2:DHE-RSA-AES256-SHA256:256
mta error reason=SSL certificate check failed
smtp-out: Disabling route [] <-> 1.2.3.4 (gmail.com) for 15s
The fix for this is to set tls no-verify
in the action like so:
action "example_bad_tls_relay" \
relay \
tls no-verify \
host smtp+tls://website@gmail.com:587 \
auth <relay_secrets> \
mail-from website@example.com
/etc/smtpd.conf in detail¶
This example /etc/smtpd.conf
goes into detail about the relevant configurations:
# Read an opensmtpd "table" (a table is like a small database file)
# Doc: https://man.openbsd.org/table
# The contents of the table "relay_secrets" declare a purpose to a specific smtp-user and -password pair
# Example:
# purpose user:password
# monitoring monitoring@example.com:secretpassword
table relay_secrets file:/etc/smtpd/tables/relay_secrets
# Declare an opensmtpd "filter"
# Doc: https://man.openbsd.org/smtpd.conf#MAIL_FILTERING
# A filter is used to either accept, reject or modify an email
filter regex_replace_data proc-exec "/etc/smtpd/filters/regex-replace-data.py"
# Only open the port on 127.0.0.1 on the loopback interface
# Doc: https://man.openbsd.org/smtpd.conf#listen
listen on lo \
# Listen on tcp port 25
# Doc: https://man.openbsd.org/smtpd.conf#port
port 25 \
# When accepting a SMTP dialogue, announce yourself as mail.example.com
# Also write mail.example.com as processing mailserver into the email header
# This hostname is also set in /etc/mailname
# Doc: https://man.openbsd.org/smtpd.conf#hostname
hostname mail.example.com \
# Apply the filter "regex_replace_data" to all emails
# Doc: https://man.openbsd.org/smtpd.conf#filter~5
filter regex_replace_data
# Listen on /var/run/smtpd.sock for SMTP connections
# Doc: https://man.openbsd.org/smtpd.conf#listen~2
listen on socket \
# Omit the from part when prepending “Received” headers
# Doc: https://man.openbsd.org/smtpd.conf#mask-src~2
mask-src \
# Assign the connection this specific tag (only used inside opensmtpd, not written to the email header)
# Doc: https://man.openbsd.org/smtpd.conf#tag~2
tag "socket" \
# Apply the filter "regex_replace_data" to all emails
# Doc: https://man.openbsd.org/smtpd.conf#filter~5
filter regex_replace_data
# Define the action "relay_monitoring"
# Doc: https://man.openbsd.org/smtpd.conf#action
action "relay_monitoring" \
# This action relays emails to another SMTP server
# Doc: https://man.openbsd.org/smtpd.conf#relay
relay \
# Require TLS when relaying
# Doc: https://man.openbsd.org/smtpd.conf#tls
tls \
# Relay the email to over this particular host
# Doc: https://man.openbsd.org/smtpd.conf#host
# Note the <monitoring> string, which refers to the line in the table "relay_secrets" we defined above!
# monitoring@example.com is NOT an email address! It is the syntax <relay_secrets_table_line>@host:port
host smtp+tls://monitoring@example.com:587 \
# For the <monitoring> relay credentials defined in the previous line, use the table relay_secrets to look up the credentials
# Doc: https://man.openbsd.org/smtpd.conf#auth
auth <relay_secrets> \
# Use the given email address as the MAIL FROM address in the SMTP transaction
# Doc: https://man.openbsd.org/smtpd.conf#MAIL FROM
MAIL FROM monitoring@example.com
# When tools, webapps, linux users and others try to relay email over opensmtpd, they always state a "MAIL FROM" line in the SMTP transaction.
# "match" lines associate MAIL FROM with a particular relay
# Doc: https://man.openbsd.org/smtpd.conf#match
match \
# Connection can only come from a local IP (127.0.0.1)
from local \
# Match "MAIL FROM: root"
MAIL FROM "root" \
# Match any destionation
for any \
# Use the action "relay_monitoring" defined above
action "relay_monitoring"
# More examples
match from local MAIL FROM "prometheus-alertmanager" for any action "relay_monitoring"
match from local MAIL FROM "grafana" for any action "relay_monitoring"
# Reject everything else
match from any reject