You may want to inform yourself about human rights in China.

On OpenBSD's Sendmail(8) and Gmail

date: 2022-07-26
update: 2022-08-03

The following explores the configuration of an OpenBSD base install to send emails from the CLI (mail(1), sendmail(8), etc.), relaying them to an existing Gmail account. We’re not touching upon reading emails here; we’ll present some tools to help with attachments.

Essential bits of smtpd(8) configuration to achieve email relaying are actually the first example setup from smtpd.conf(5):

EXAMPLES
     The default smtpd.conf file which ships with OpenBSD listens on the
     loopback network interface (lo0) and allows for mail from users and
     daemons on the local machine, as well as permitting email to remote
     servers.  Some more complex configurations are given below.

     This first example is similar to the default configuration, but all
     outgoing mail is forwarded to a remote SMTP server.  A secrets file is
     needed to specify a username and password:

           # touch /etc/mail/secrets
           # chmod 640 /etc/mail/secrets
           # chown root:_smtpd /etc/mail/secrets
           # echo "bob username:password" > /etc/mail/secrets

     smtpd.conf would look like this:

           table aliases file:/etc/mail/aliases
           table secrets file:/etc/mail/secrets

           listen on lo0

           action "local_mail" mbox alias <aliases>
           action "outbound" relay host smtp+tls://bob@smtp.example.com \
                   auth <secrets>

           match from local for local action "local_mail"
           match from local for any action "outbound"

The Heracles papyrus; note on the right, a drawing of the killing of the Nemean lion by Heracles

The Heracles papyrus; note on the right, a drawing of the killing of the Nemean lion by Heracles through wikimedia.orgPublic domain

Gmail account setup

In order,

  1. you first need to make sure that the 2-Step Verification is enabled for your account (this should be enabled by default);
  2. you’ll then be able to create app passwords for your account by going on your personal App passwords page.

The previous links should be clear enough on the exact procedure; bear in mind that the application name only has a self-documentation use. In the end, this should yield a 16 ASCII lowercase letters password; we’ll assume from now on:

smtpd(8), smtpd.conf(5)

We can then configure smtpd(8); the default /etc/mail/smtpd.conf looks something like:

#       $OpenBSD: smtpd.conf,v 1.14 2019/11/26 20:14:38 gilles Exp $

# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.

table aliases file:/etc/mail/aliases

listen on socket

# To accept external mail, replace with: listen on all
#
listen on lo0

action "local_mail" mbox alias <aliases>
action "outbound" relay

# Uncomment the following to accept external mail for domain "example.org"
#
# match from any for domain "example.org" action "local_mail"
match from local for local action "local_mail"
match from local for any action "outbound"

Relevant bits from smtpd.conf(5):

DESCRIPTION

     ...

     action name method [options]
             When the queue runner processes an envelope from the mail queue,
             it carries out the action name, selected by the match ... action
             directive when the message was received.  The action directive
             provides configuration data for delivery attempts.  Required
             lookups are performed at the time of each delivery attempt.
             Consequently, changing an action directive or the files it
             references and restarting the smtpd(8) daemon causes the changes
             to take effect for subsequent delivery attempts for the
             respective dispatcher name, even for messages that were already
             stuck in the queue prior to the configuration changes.

             The delivery method parameter may be one of the following:

             ...

             relay   Relay the message to another SMTP server.

             The local delivery methods support additional options:

             ...

             host relay-url
                     Do not perform MX lookups but relay messages to the relay
                     host described by relay-url.  The format for relay-url is
                     [proto://[label@]]host[:port].  The following protocols
                     are available:

                     smtp        Normal SMTP session with opportunistic
                                 STARTTLS (the default).
                     smtp+tls    Normal SMTP session with mandatory STARTTLS.
                     smtp+notls  Plain text SMTP session without TLS.
                     lmtp        LMTP session.  port is required.
                     smtps       SMTP session with forced TLS on connection.
                                 The default port is 465.

                     Unless noted, port defaults to 25.

                     The label corresponds to an entry in a credentials table,
                     as documented in table(5).  It is used with the
                     "smtp+tls" and "smtps" protocols for authentication.
                     Server certificates for those protocols are verified by
                     default.

             ...

             auth <table>
                     Use the mapping table for connecting to relay-url using
                     credentials.  This option is usable only with host
                     option.  The credential table format is described in
                     table(5).

     ...

     match options action name
             If at least one mail envelope matches the options of one match
             action directive, receive the incoming message, put a copy into
             each matching envelope, and atomically save the envelopes to the
             mail spool for later processing by the respective dispatcher
             name.

             [!] for any
                     Specify that session may address any destination.

             ...

             [!] from local
                     Specify that session may only originate from a local IP
                     address, or from the local enqueuer.  This is the
                     default, and may be omitted.

     ...

     table name [type:]pathname
             Tables provide additional configuration information for smtpd(8)
             in the form of lists or key-value mappings.  The format of the
             entries depends on what the table is used for.  Refer to table(5)
             for the exhaustive documentation.

             Each table is identified by an arbitrary, unique name.

             If the type is db, information is stored in a file created with
             makemap(8); if it is file or omitted, information is stored in a
             plain text file using the format described in table(5).  The
             pathname to the file must be absolute.

As suggested by smtpd.conf(5), we’ll want to add to /etc/mail/smtpd.conf a new table containing our secret:

table secrets file:/etc/mail/secrets

The /etc/mail/secrets itself can be created as such:

(server); echo 'entryname foobar@gmail.com:jbvypwimgctkcgaz' > /etc/mail/secrets
(server); chown root:_smtpd                                    /etc/mail/secrets
(server); chmod 640                                            /etc/mail/secrets

Going back to /etc/mail/smtpd.conf, we now need to inform smtpd(8) that it needs to relay all outbound mails through this gmail account, which will be implemented with such two lines:

action "relay"      relay host smtp+tls://entryname@smtp.gmail.com:587 auth <secrets>
match from local for any   action "relay"

Which in the end gives us for /etc/mail/smtpd.conf something like:

# This is the smtpd server system-wide configuration file.
# See smtpd.conf(5) for more information.

table aliases file:/etc/mail/aliases
table secrets file:/etc/mail/secrets

listen on socket

# To accept external mail, replace with: listen on all
#
listen on lo0

action "local_mail" mbox  alias <aliases>
action "relay"      relay host smtp+tls://entryname@smtp.gmail.com:587 auth <secrets>

# Uncomment the following to accept external mail for domain "example.org"
#
# match from any for domain "example.org" action "local"
match from local for local action "local_mail"
match from local for any   action "relay"

You may now check the configuration file, restart smtpd(8), and try sending an email, while inspecting relevant logs:

# Checking smtpd.conf...
(server); smtpd -n

# Restarting smtpd...
(server); rcctl restart smtpd

# Display smtpd logs on console
(server); tail -f -n 0 /var/log/maillog &

# Send test mail
(server); echo foo | mail -s bar foobar@gmail.com

# Logs displayed by the tail(1)
2022-07-25T23:06:42.400Z main smtpd[36237]: fa7d3d2223174777 smtp message msgid=d9680942 size=377 nrcpt=1 proto=ESMTP
2022-07-25T23:06:42.400Z main smtpd[36237]: fa7d3d2223174777 smtp envelope evpid=d968094237ae067f from=<root@main.openstacklocal> to=<foobar@gmail.com>
2022-07-25T23:06:42.400Z main smtpd[36237]: fa7d3d2223174777 smtp disconnected reason=quit
2022-07-25T23:06:42.406Z main smtpd[36237]: fa7d3d2672071d9e mta connecting address=smtp+tls://108.177.127.109:587 host=el-in-f109.1e100.net
2022-07-25T23:06:42.419Z main smtpd[36237]: fa7d3d2672071d9e mta connected
2022-07-25T23:06:42.503Z main smtpd[36237]: fa7d3d2672071d9e mta tls ciphers=TLSv1.3:TLS_AES_256_GCM_SHA384:256
2022-07-25T23:06:42.503Z main smtpd[36237]: fa7d3d2672071d9e mta cert-check result="valid" fingerprint="SHA256:3858f62230ac3c915f300c664312c63f3858f62230ac3c915f300c664312c63f"
2022-07-25T23:06:43.406Z main smtpd[36237]: fa7d3d2672071d9e mta delivery evpid=d968094237ae067f from=<root@main.openstacklocal> to=<foobar@gmail.com> rcpt=<-> source="1.1.1.1" relay="108.177.127.109 (el-in-f109.1e100.net)" delay=1s result="Ok" stat="250 2.0.0 OK  1658790403 f23-20020a17090631d700b0072b55713daesm5693643ejf.56 - gsmtp"
2022-07-25T23:06:53.517Z main smtpd[36237]: fa7d3d2672071d9e mta disconnected reason=quit messages=1

MIME mails

By default, OpenBSD only comes with uuencode(1) to help sending emails with attachments, based on an essentially deprecated 1980s software, and which are poorly displayed by Gmail. It is typically used as such:

(
	echo Subject: [name] backup -- $date
	echo "\r\n"
	uuencode /path/to/backup.tgz name-$date.tgz
) | sendmail -f $from $to
To the left, Anubis brings Hunefer into the judgement area. Anubis is also shown supervizing the judgement scales. Hunefer’s heart, represented as a pot, is being weighed against a feather, the symbol of Maat, the established order of things, in this context meaning ‘what is right’.

To the left, Anubis brings Hunefer into the judgement area. Anubis is also shown supervizing the judgement scales. Hunefer’s heart, represented as a pot, is being weighed against a feather, the symbol of Maat, the established order of things, in this context meaning ‘what is right’. through wikimedia.orgPublic domain

An alternative is to use the MIME (Multipurpose Internet Mail Extensions) format: in particular, this daemonforums.org post by Adriaan van Roosmalen (J65nko) presents the format, and provides a small sh(1) tool, matts, to actually send MIME emails.

Note: I’ve actually used matts as a base to wrote a similar wrapper mmail, which as a main difference, allows to set arbitrary headers.

Forwarding cronjobs mail

By default, cronjobs’s output is sent to the local mail box of the crontab(1) owner. The behavior can be overidden by setting the MAILTO environment variable in the crontab(5):

ENVIRONMENT

     ...

     MAILTO      If MAILTO is defined and non-empty, mail is sent to the user
                 so named.  If MAILTO is defined but empty (MAILTO = ""), no
                 mail will be sent.  Otherwise mail is sent to the owner of
                 the crontab.  This is useful for pseudo-users that lack an
                 alias that would otherwise redirect the mail to a real
                 person.

By setting a non-local address, smtpd(8) will automatically relay the email, so the following crontab will send cronjobs output by email to our gmail address:

#
SHELL=/bin/sh
HOME=/var/log
SUGARD=/var/sugard
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/var/sugard/bin
MAILTO=foobar@gmail.com
#
#minute hour    mday    month   wday    [flags] command
#
# rotate log files every hour, if necessary
0       *       *       *       *       /usr/bin/newsyslog

...

00     00       *       *       *       /bin/sh $SUGARD/bin/renew-certs     >/dev/null
30     00       *       *       *       /bin/sh $SUGARD/bin/backup-certs    >/dev/null
00     00       *       *       *       /bin/sh $SUGARD/bin/get-ip2location >/dev/null

sugar(1)

For the record, the setup (smtpd, mmail) can be simply automated with sugar(1): see the dedicated OpenBSD repository.

% sugar -s box setup-gmail
hook-pre-setup-gmail                    : Preparing mail/secrets for sync...
setup-gmail                             : Installing mail/secrets and smtpd.conf...
setup-gmail                             : Checking smtpd.conf...
setup-gmail                             : Restarting smtpd...
OK
% sugar -s main setup-mmail
hook-pre-setup-mmail                    : Asserting mmail is locally installed...
hook-pre-setup-mmail                    : Preparing mmail for sync...
setup-mmail                             : Installing mmail...
setup-mmail                             : Updating mandoc.db...
OK

For more about sugar, see:


Comments

By email, at mathieu.bivert chez:

email