Observing SMTP

You can easily observe exchanges between your computer and your SMTP server, whether you wish to troubleshoot or just explore. There are several able commands for your toolkit. These notes favor swaks: "Swiss Army Knife SMTP, the all-purpose smtp transaction tester" (quoted from its man page). It's designed for this inspection. Both mailx and msmtp offer a verbose mode, which displays a session transcript. For all three, you submit a command expressing your wishes and get a transcript of what happens. Alternatively, if you'd like to interact with the server by entering SMTP commands explicitly, one by one, you can use telnet for plaintext servers or openssl for TLS servers.

Test Rig

Both client and server run on the same computer, localhost (127.0.0.1), which happens to be a Fedora desktop. Neither a common host nor Fedora is necessary; this platform just suits my convenience and resources.

The client side is a terminal where an ordinary user (e.g., ray) submits swaks or other commands to the server and manages exchanged email.

The server side consists of two root shells running OpenSMTPD programs. The firsts runs the SMTP server smtpd in the foreground (i.e., not as a daemon) so that status messages are echoed. The second runs smtpctl to stop, query, and sometimes adjust the running server.

The SMTP server has two configurations that differ only with respect to authentication. Both listen on ports 25, 465, and 587. Port 25 eschews TLS and hence authentication; port 465 requires SMTPS; port 587 requires STARTTLS. In one configuration, ports 465 and 587 do not support authentication. In the other configuration, these ports require authentication. (Authentication on ports 465 and 587 is not actually coupled.)

The client sends messages from Alice to Bob, and the server delivers these to /tmp/Maildir/bob. You can manage Bob's inbox with mailx by locating the directory like so:

-> MAIL=/tmp/Maildir/bob mailx

Here is the complete configuration file for the test rig's server, smtpd-testrig.conf:

pki desktop certificate "/etc/opensmtpd/smtp-cert.pem"
pki desktop key         "/etc/opensmtpd/smtp-key.pem"

# Passwords are "123" for Alice and "abc" for Bob (without quotation marks).
table users {\
   alice = '$6$9W/lcP4b0mWuw44j$cSJU3T/uepnF56v7yyZn7l6BOE51cNyDi3wdi.zJEmnVEw1JjHDcEGY9NHlen1gtMvKQ4Is2Lbvr8mMFTpnvh0' \
   bob   = '$6$G85H/Z0PnF6ZyXha$T614udxonNZEvZNgkg52QrUgVC90tV/FDOeNbsr3hL9pmjaR1odL5Ow/P9yK3EPIxCv4G3ZTAwMq8Nk0yhNLU/' \
}

listen on localhost port  25  hostname "Test Rig"
## Activate one of the following two rules:
listen on localhost port 465  hostname "Test Rig"  smtps       pki desktop
#listen on localhost port 465  hostname "Test Rig"  smtps       pki desktop  auth <users>
## Activate one of the following two rules:
listen on localhost port 587  hostname "Test Rig"  tls-require pki desktop
#listen on localhost port 587  hostname "Test Rig"  tls-require pki desktop  auth <users>

# Serve users Alice and Bob (only).
# Put mail to Alice in /tmp/Maildir/alice
# Put mail to Boob  in /tmp/Maildir/bob
table userinfo {\
      alice = 1000:1000:/home/ray \
      bob   = 1000:1000:/home/ray \
}
accept from local  for any  userbase <userinfo>  deliver to maildir "/tmp/Maildir/%{user.username}"

You can have your installed instance of swaks report what SMTP features it supports:

-> swaks --support
=== AUTH CRAM-MD5 supported
=== AUTH CRAM-SHA1 supported
*** AUTH DIGEST-MD5 not available: requires Authen::SASL
=== AUTH NTLM supported
=== Basic AUTH supported
=== Date Manipulation supported
=== High Resolution Timing supported
*** IPv6 not available: requires IO::Socket::INET6
=== Local Hostname Detection supported
=== MX Routing supported
=== Pipe Transport supported
=== Socket Transport supported
=== TLS supported

swaks is a Perl program, and the stars above illuminate missing Perl modules. You can remedy omissions by installing these modules. For example:

=> dnf install perl-Authen-SASL perl-IO-Socket-INET6 --quiet --assumeyes

You won't see stars anymore.

Open

To start simply, send a message to an anything-goes server, which skips both TLS and authentication. It listens on port 25 and identifies itself as "Test Rig":

-> swaks --server localhost:25 --from alice@localhost --to bob@localhost --suppress-data | cat --number
     1	=== Trying localhost:25...
     2	=== Connected to localhost.
     3	<-  220 Test Rig ESMTP OpenSMTPD
     4	 -> EHLO desktop.home
     5	<-  250-Test Rig Hello desktop.home [127.0.0.1], pleased to meet you
     6	<-  250-8BITMIME
     7	<-  250-ENHANCEDSTATUSCODES
     8	<-  250-SIZE 36700160
     9	<-  250-DSN
    10	<-  250 HELP
    11	 -> MAIL FROM:<alice@localhost>
    12	<-  250 2.0.0: Ok
    13	 -> RCPT TO:<bob@localhost>
    14	<-  250 2.1.5 Destination address valid: Recipient ok
    15	 -> DATA
    16	<-  354 Enter mail, end with "." on a line by itself
    17	 -> 9 lines sent
    18	<-  250 2.0.0: e4adab07 Message accepted for delivery
    19	 -> QUIT
    20	<-  221 2.0.0: Bye
    21	=== Connection closed with remote host.

In addition to sending email, swaks reports a transcript of its communication with the server. Each line of the transcript begins with a prefix identifying its source: Prefix "===" denotes information from swaks itself; prefix "->" denotes a command or data sent from the client to the server; prefix "<-" denotes a response from the server to the client. When swaks is ready to send the actual message (lines 15–18)), it conveniently generates simple content, which the transcript abbreviates as "9 lines sent" (--suppress-data).

The client identifies itself in the EHLO command, and the server repeats this name in its greeting (lines 4–5). In the absence of instructions otherwise, swaks uses the host's name for the client:

-> hostname --long
desktop.home

You can overrule that choice with option --ehlo (-h); for example:

-> swaks --server localhost:25 --ehlo Swaks --from alice@localhost --to bob@localhost --suppress-data | cat --number

     4	 -> EHLO Swaks
     5	<-  250-Test Rig Hello Swaks [127.0.0.1], pleased to meet you

Now the client goes by "Swaks". That's the whole, cosmetic scoop; there's no further effect or deeper implication.

You can use shorter options with swaks (and cat):

-> swaks -s localhost:25 -h Swaks -f alice@localhost -t bob@localhost -n | cat -n

You can also put constant options into a configuration file once and for all. The examples on this page send a message from Alice to Bob on localhost, so put the corresponding options into file swaks-testrig.conf, say,

-> cat swaks-testrig.conf
--server localhost
--ehlo Swaks
--from alice@localhost
--to bob@localhost
--suppress-data

The server name above drops the port number because that varies. And you need to extirpate extra whitespace because swaks apparently takes that literally. Now:

-> swaks --config swaks-testrig.conf --port 25 | cat --number

Or:

-> swaks --config swaks-testrig.conf -p 25 | cat -n

There's no abbreviation for --config, though.

SMTPS

This example sends an email to a server requiring SMTPS—that is, SMTP tunneled through TLS from the get go. The server listens on port 465. Option --tls-on-connect tells swaks to use SMTPS.

-> swaks --server localhost:465 --tls-on-connect --from alice@localhost --to bob@localhost --suppress-data | cat -n
     1	=== Trying localhost:465...
     2	=== Connected to localhost.
     3	=== TLS started with cipher TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128
     4	=== TLS no local certificate set
     5	=== TLS peer DN="/C=XX/L=Default City/O=Default Company Ltd"
     6	<~  220 Test Rig ESMTP OpenSMTPD
     7	 ~> EHLO desktop.home
     8	<~  250-Test Rig Hello desktop.home [127.0.0.1], pleased to meet you
     9	<~  250-8BITMIME
    10	<~  250-ENHANCEDSTATUSCODES
    11	<~  250-SIZE 36700160
    12	<~  250-DSN
    13	<~  250 HELP
    14	 ~> MAIL FROM:<alice@localhost>
    15	<~  250 2.0.0: Ok
    16	 ~> RCPT TO:<bob@localhost>
    17	<~  250 2.1.5 Destination address valid: Recipient ok
    18	 ~> DATA
    19	<~  354 Enter mail, end with "." on a line by itself
    20	 ~> 9 lines sent
    21	<~  250 2.0.0: 21ddf94a Message accepted for delivery
    22	 ~> QUIT
    23	<~  221 2.0.0: Bye
    24	=== Connection closed with remote host.

The transcript introduces another pair of prefixes "~>" and "<~" (with tildes replacing hyphens) to denote encrypted exchanges between client and server.

Here the client and server establish a TLS channel at the outset and encrypt all subsequent dialog through this channel. Thus, note the absence of STARTTLS in the list of features (lines 7–13) that the server remits in response to the EHLO command—STARTTLS would be redundant.

You can abbreviate the swaks command this-a way:

-> swaks --config swaks-testrig.conf -p 465 -tlsc

The transcript reports only briefly on the server's remitted certificate (line 5). You can use option --tls-get-peer-cert to save a copy of this certificate in a file of your choice for subsequent review. And if that's all you're after, you may as well add option --quit-after TLS:

-> swaks --server localhost:465 -tlsc --tls-get-peer-cert /tmp/testrig.pem --quit-after tls
=== Trying localhost:465...
=== Connected to localhost.
=== TLS started with cipher TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128
=== TLS no local certificate set
=== TLS peer DN="/C=XX/L=Default City/O=Default Company Ltd"
 ~> QUIT
<~* 220 Test Rig ESMTP OpenSMTPD
=== Connection closed with remote host.

This puts the certificate in /tmp/testrig.pem without comment. You can examine the certificate with certtool or openssl:

-> certtool --certificate-info --infile /tmp/testrig.pem
Certificate details for Test Rig
-> openssl x509 -in /tmp/testrig.pem -text -noout
Certificate details for Test Rig

If you drop the file name after option --tls-get-peer-cert, swaks embeds the certificate's PEM block in the transcript.

->  swaks --server localhost:465 -tlsc --tls-get-peer-cert --quit-after TLS
=== Trying localhost:465...
=== Connected to localhost.
=== TLS started with cipher TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128
=== TLS no local certificate set
=== TLS peer DN="/C=XX/L=Default City/O=Default Company Ltd"
=== -----BEGIN CERTIFICATE-----
text/base64 rendition of certificate's binary data stream goes here
=== -----END CERTIFICATE-----
 ~> QUIT
<~* 220 Test Rig ESMTP OpenSMTPD
=== Connection closed with remote host.

If you want swaks to verify the server's certificate, include option --tls-verify and possibly --tls-ca-path. Otherwise, it trusts the certificate's public key for encrypting the session.

STARTTLS

This example sends an email to a server requiring STARTTLS. The server listens on port 587. Option -tls tells swaks to use STARTTLS.

-> swaks --server localhost:587 -tls --from alice@localhost --to bob@localhost --suppress-data | cat -n
     1	=== Trying localhost:587...
     2	=== Connected to localhost.
     3	<-  220 Test Rig ESMTP OpenSMTPD
     4	 -> EHLO desktop.home
     5	<-  250-Test Rig Hello desktop.home [127.0.0.1], pleased to meet you
     6	<-  250-8BITMIME
     7	<-  250-ENHANCEDSTATUSCODES
     8	<-  250-SIZE 36700160
     9	<-  250-DSN
    10	<-  250-STARTTLS
    11	<-  250 HELP
    12	 -> STARTTLS
    13	<-  220 2.0.0: Ready to start TLS
    14	=== TLS started with cipher TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128
    15	=== TLS no local certificate set
    16	=== TLS peer DN="/C=XX/L=Default City/O=Default Company Ltd"
    17	 ~> EHLO desktop.home
    18	<~  250-Test Rig Hello desktop.home [127.0.0.1], pleased to meet you
    19	<~  250-8BITMIME
    20	<~  250-ENHANCEDSTATUSCODES
    21	<~  250-SIZE 36700160
    22	<~  250-DSN
    23	<~  250 HELP
    24	 ~> MAIL FROM:<alice@localhost>
    25	<~  250 2.0.0: Ok
    26	 ~> RCPT TO:<bob@localhost>
    27	<~  250 2.1.5 Destination address valid: Recipient ok
    28	 ~> DATA
    29	<~  354 Enter mail, end with "." on a line by itself
    30	 ~> 9 lines sent
    31	<~  250 2.0.0: cc4a2343 Message accepted for delivery
    32	 ~> QUIT
    33	<~  221 2.0.0: Bye
    34	=== Connection closed with remote host.

Note the lack of encryption prior to the STARTTLS command (lines 12–13) and the encryption following STARTTLS. Also note the pair of EHLO commands and their remitted features (lines 4–12 and 17–23). The list before encryption includes STARTTLS, and the list after encryption omits STARTTLS.

You can abbreviate the swaks command:

-> swaks --config swaks-testrig.conf -p 587 -tls

Authenitcation

In this example, the server requires authentication, in addition to SMTPS. It listens on port 465.

-> swaks --server localhost:465 --tls-on-connect --auth plain --auth-user alice --auth-password 123 \
   --from alice@localhost --to bob@localhost --suppress-data | cat -n
     1	=== Trying localhost:465...
     2	=== Connected to localhost.
     3	=== TLS started with cipher TLSv1.2:ECDHE-RSA-AES128-GCM-SHA256:128
     4	=== TLS no local certificate set
     5	=== TLS peer DN="/C=XX/L=Default City/O=Default Company Ltd"
     6	<~  220 Test Rig ESMTP OpenSMTPD
     7	 ~> EHLO desktop.home
     8	<~  250-Test Rig Hello desktop.home [127.0.0.1], pleased to meet you
     9	<~  250-8BITMIME
    10	<~  250-ENHANCEDSTATUSCODES
    11	<~  250-SIZE 36700160
    12	<~  250-DSN
    13	<~  250-AUTH PLAIN LOGIN
    14	<~  250 HELP
    15	 ~> AUTH PLAIN AGFsaWNlADEyMw==
    16	<~  235 2.0.0: Authentication succeeded
    
    27	=== Connection closed with remote host.

This server supports two methods of authentication, PLAIN and LOGIN (line 13). Both expect the client to remit a username and password as plaintext. The methods differ only slightly in packaging; example below. Since the TLS channel protects communication, credentials need no further protection. For a STARTTLS transaction, authentication follows TLS.

The client sends the username and password with the AUTH PLAIN command (line 15). The command's argument encodes (not encrypts!) these in base64:

-> echo AGFsaWNlADEyMw== | base64 --decode; echo
alice123

You would not want to expose a real password in a published transcript, of course. You can include option --auth-hide-password (-ahp) to replace the password with "PROVIDED_BUT_REMOVED" in the transcript. You get the following instead:

 ~> AUTH PLAIN AGFsaWNlAFBST1ZJREVEX0JVVF9SRU1PVkVE
<~  235 2.0.0: Authentication succeeded

And now your secret is safe:

-> echo AGFsaWNlAFBST1ZJREVEX0JVVF9SRU1PVkVE | base64 --decode; echo
alicePROVIDED_BUT_REMOVED

You can get swaks to do the decoding for you by adding option --auth-plaintext (-apt) , which tells the transcript to show authentication as plaintext:

 ~> AUTH PLAIN \0alice\0123
 ~> AUTH PLAIN \0alice\0PROVIDED_BUT_REMOVED

You can abbreviate the swaks command like this:

-> swaks --config swaks-testrig.conf -p 465 -tlsc -a plain -au alice -ap 123

You can choose the LOGIN method instead of PLAIN with option --auth login (-a login) instead of --auth plain. This amounts to a wordier dialog than PLAIN uses. With --auth-plaintext as well, you see this:

 ~> AUTH LOGIN
<~  334 Username:
 ~> alice
<~  334 Password:
 ~> 123
<~  235 2.0.0: Authentication succeeded

You can have swaks prompt you for the username, password, or both by omitting the corresponding options --auth-user and --auth-password. For example:

-> swaks --config swaks-testrig.conf -p 465 -tlsc --auth plain
Username: alice
Password: 123

You may want to cover up that naked password with option --protect-prompt:

-> swaks --config swaks-testrig.conf -p 465 -tlsc --auth plain --protect-prompt
Username: alice
Password: ***

The length of the password does show through this scanty cover, alas.

And if you lack a preference for the authentication method, let swaks decide by omitting the argument to option --auth:

-> swaks --config swaks-testrig.conf -p 465 -tlsc --auth

 ~> AUTH LOGIN

If you are debugging authentication, you might like option --quit-after auth.

Telnet Alternative

You can use telnet to connect to a plaintext SMTP server, submit SMTP commands manually, and view the server's responses. Here's a transcript of a session in which Alice sends a short test message to Bob. Commands and data you enter are highlighted thus; responses from the server begin with a three-digit number; remaining lines come from telnet. The server runs on localhost and listens on port 25:

-> telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 Test Rig ESMTP OpenSMTPD
ehlo Telnet
250-Test Rig Hello Telnet [127.0.0.1], pleased to meet you
250-8BITMIME
250-ENHANCEDSTATUSCODES
250-SIZE 36700160
250-DSN
250 HELP
mail from: <alice@localhost>
250 2.0.0: Ok
rcpt to: <bob@localhost>
250 2.1.5 Destination address valid: Recipient ok
data
354 Enter mail, end with "." on a line by itself
From: Alice@localhost
To: Bob@localhost
Subject: Test

Hello there.
.
250 2.0.0: 70e2d5b4 Message accepted for delivery
quit
221 2.0.0: Bye
Connection closed by foreign host.

You can use telnet for initial interaction with a STARTTLS server because communication begins as plaintext. You wont's get far, however. Once you issue the STARTTLS command, you'll be stuck (ostensibly).

You cannot connect to an SMTPS server with telnet because that communication requires TLS from soup to nuts.

OpenSSL Alternative

You can use openssl to interact manually with an SMTP server requiring TLS, whether SMTPS or STARTTLS. For an SMTPS server running on localhost and listening on port 465, use this command:

-> openssl s_client -quiet -connect localhost:465
depth=0 C = XX, L = Default City, O = Default Company Ltd
verify error:num=18:self signed certificate
verify return:1
depth=0 C = XX, L = Default City, O = Default Company Ltd
verify return:1
220 Test Rig ESMTP OpenSMTPD

And for a STARTTLS server listening on port 587, use this command:

-> openssl s_client -quiet -connect localhost:587 -starttls smtp
depth=0 C = XX, L = Default City, O = Default Company Ltd
verify error:num=18:self signed certificate
verify return:1
depth=0 C = XX, L = Default City, O = Default Company Ltd
verify return:1
250 HELP

In either case, your SMTP channel is now established and protected. You issue SMTP commands in plaintext and see the server's responses in plaintext, courtesy of openssl, just as you would for an open telnet session.

If you want to see more TLS information underlying your connection, drop option -quiet above.

Mailx Alternative

You can observe SMTP transactions while sending an email with Heirloom mailx. Here is an example in which Alice sends a test message to Bob via the open server (no TLS, no authentication). Configuration file mailx-testrig.conf specifies the test rig's details, and file msg-testrig provides the email message.

-> export MAILRC=./mailx-testrig.conf
-> mailx -t -A open < msg-testrig
Resolving host localhost . . . done.
Connecting to 127.0.0.1:25 . . . connected.
220 Test Rig ESMTP OpenSMTPD
>>> HELO mailx
250 Test Rig Hello mailx [127.0.0.1], pleased to meet you
>>> MAIL FROM:<alice@localhost>
250 2.0.0: Ok
>>> RCPT TO:<bob@localhost>
250 2.1.5 Destination address valid: Recipient ok
>>> DATA
354 Enter mail, end with "." on a line by itself
>>> .
250 2.0.0: c12a1d92 Message accepted for delivery
>>> QUIT
221 2.0.0: Bye

Here mailx reports a transcript of its communication with the server because its configuration file tells it to. A line with prefix ">>>" show a command or data sent to the server by mailx. A line beginning with three digits shows a response remitted by the server. Other lines are commentary from mailx itself.

You need to guide mailx to a non-default configuration file, like mailx-testrig.conf, and that's what the MAILX environment does above—in a Bash shell. You can limit the scope of this definition:

-> MAILRC=./mailx-testrig.conf mailx -t -A open < msg-testrig

For the record:

-> cat msg-testrig
From: Alice <alice@localhost>
To: Bob <bob@localhost>
Subject: Testing 

Hello there.

Option -t tells mailx to find all recipients by reading the email to be sent. In this case, it finds Bob.

The configuration file mailx-testrig.conf defines five mailx accounts corresponding to the five test-rig servers: open, SMTPS, STARTTLS, SMTPS plus authentication, and STARTTLS plus authentication. It also sets a few parameters for the client side.

set verbose=yes
set DEAD=/tmp/dead.letter
set hostname=mailx
set from="Alice <alice@localhost>"
set ssl-verify=ignore
set nss-config-dir=/etc/pki/nssdb

account open {
   set smtp=localhost:25
}
account smtps {
   set smtp=smtps://localhost:465
}
account starttls {
   set smtp=localhost:587
   set smtp-use-starttls=yes
}
account smtps-auth {
   set smtp=smtps://localhost:465
   set smtp-auth=plain
   set smtp-auth-user=alice
   set smtp-auth-password=123
}
account starttls-auth {
   set smtp=localhost:587
   set smtp-use-starttls=yes
   set smtp-auth=plain
   set smtp-auth-user=alice
   set smtp-auth-password=123
}
account open 

You pick the test rig simply by naming its account with option -A:

-> export MAILRC=./mailx-testrig.conf
-> mailx -t -A open          < msg-testrig
-> mailx -t -A smtps         < msg-testrig
-> mailx -t -A starttls      < msg-testrig
-> mailx -t -A smtps-auth    < msg-testrig
-> mailx -t -A starttls-auth < msg-testrig

MSMTP Alternative

You can observe SMTP transactions while sending an email with MSMTP: Call msmtp directly—rather than implicitly in its usual, under-the-hood role as a replacement for Sendmail. Just include option -v to get a report on your transaction. Here is an example in which Alice sends yet another test message to beleaguered Bob via the open server (no TLS, no authentication). Configuration file msmtp-testrig.conf specifies the test rig's details, and file msg-testrig provides the email message.

-> msmtp -v --file msmtp-testrig.conf --read-recipients --account open < msg-testrig

msmtp reports its run-time parameters here

<-- 220 Test Rig ESMTP OpenSMTPD
--> EHLO msmtp
<-- 250-Test Rig Hello msmtp [127.0.0.1], pleased to meet you
<-- 250-8BITMIME
<-- 250-ENHANCEDSTATUSCODES
<-- 250-SIZE 36700160
<-- 250-DSN
<-- 250 HELP
--> MAIL FROM:<alice@localhost>
<-- 250 2.0.0: Ok
--> RCPT TO:<bob@localhost>
<-- 250 2.1.5 Destination address valid: Recipient ok
--> DATA
<-- 354 Enter mail, end with "." on a line by itself
--> From: Alice <alice@localhost>
--> To: Bob <bob@localhost>
--> Subject: Testing 
--> 
--> Hello there.
--> .
<-- 250 2.0.0: ec6d9f6a Message accepted for delivery
--> QUIT
<-- 221 2.0.0: Bye

In addition to showing its execution parameters and sending the message, msmtp reports a transcript of its communication with the server. Each line of the transcript begins with a prefix identifying its source: Prefix "-->" denotes a command or data sent from the client to the server; prefix "<--" denotes a response from the server to the client. The same prefixes are used in transcripts of TLS exchanges.

You can abbreviate the call somewhat:

-> msmtp -v -C msmtp-testrig.conf --read-recipients -a open < msg-testrig

For the record:

-> cat msg-testrig
From: Alice <alice@localhost>
To: Bob <bob@localhost>
Subject: Testing 

Hello there.

Option --read-recipients tells msmtp to find all recipients by reading the email to be sent. In this case, it finds Bob.

The configuration file msmtp-testrig.conf defines five MSMTP accounts corresponding to the five test-rig servers: open, SMTPS, SMTPS plus authentication, STARTTLS, and STARTTLS plus authentication. It also sets a few parameters for the client side.

defaults
host           localhost
domain         msmtp
from           alice@localhost
tls_certcheck off
auth	      off
user          alice
password      123
#--- No TLS, no auth; port 25.
account       open
port          25
tls           off
tls_starttls  off
#--- SMTPS, no auth; port 465
account       smtps
port          465
tls           on
tls_starttls  off
#--- SMTPS, auth; port 465
account      smtps-auth : smtps
auth         plain
#--- STARTTLS, no auth; port 587
account       starttls
port          587
tls           on
tls_starttls  on
#--- STARTTLS, auth; port 587
account	      starttls-auth : starttls
auth          plain
#--- Default account
account default : open

You pick the test rig simply by naming its account with option --account (-a):

-> msmtp -v -C msmtp-testrig.conf --read-recipients --account open          < msg-testrig
-> msmtp -v -C msmtp-testrig.conf --read-recipients --account smtps         < msg-testrig
-> msmtp -v -C msmtp-testrig.conf --read-recipients --account starttls      < msg-testrig
-> msmtp -v -C msmtp-testrig.conf --read-recipients --account smtps-auth    < msg-testrig
-> msmtp -v -C msmtp-testrig.conf --read-recipients --account starttls-auth < msg-testrig