Good Ingredients

Testing Mail Servers

Recipes > Core Recipes > .. > Testing Mail Servers

Over the last couple of weeks I've designing a mail infrastructure for a production system. As part of the implementation I wanted to be able to test all the settings from the command line to make sure everything was working. In this document I'll explain the different options you can have and how to test them.

Testing Unauthenticated, Unencrypted SMTP

In a correct setup this should only work when you connect from the same server which is running the SMTP server. It it works from a remote computer then the server is an open relay which means spammers can use your server to send their spam. This will result in your server quickly becoming blacklisted and after that you'll find that many legitimate e-mails you send from it will be marked as spam in the recipient's inboxes.

From localhost

First try from the local machine:

$ telnet localhost smtp

Here's what you type:

ehlo plpb.example.com
mail from:<james@example.org>
rcpt to:<james@example.com>
data
Hi James

This is a test message, testing sending mail via unencrypted SMTP
from the same machine as the SMTP server without logging in.

James
.

Make sure the address in the rcpt to line isn't one that is used by email addresses hosted by the local machine because it should accept these anyway. Also you must press Enter after the dot on its own. Since you connected from a local machine this should work.

Here's the complete output when I ran this test:

220 plpb.example.com ESMTP Postfix (Debian/GNU)
ehlo plpb.example.com
250-plpb.example.com
250-PIPELINING
250-SIZE 30720000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
mail from:<james@example.org>
250 2.1.0 Ok
rcpt to:<james@example.com>
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
Hi James

This is a test message, testing sending mail via unencrypted SMTP
from the same machine as the SMTP server without logging in.

James
.
250 2.0.0 Ok: queued as 217083C8C1

Once the message is queued type quit to exit telnet. In a few seconds the email should arrive in your inbox.

Tip

If you are running this from a local virtual machine for test purposes there is a chance your ISP, like mine seems to have blocked DNS lookups so you'll see an error like this in /var/log/syslog:

May 24 13:14:07 plpb postfix/smtp[706]: 217083C8C1: to=<james@example.com>,
relay=none, delay=419, delays=399/0.11/20/0, dsn=4.4.3, status=deferred
(Host or domain name not found. Name service error for name=example.com
type=MX: Host not found, try again)

It would probably work in real life though.

From a Remote Machine to a Known Address

Now try the same but from another machine. You should run two tests, one with a rcpt to line containing an email address hosted by the mail server and one containing an external email address. You should find you are able to send any emails destined for addresses the mail server hosts (otherwise you'd never be able to recieve mail from the outside world either) but that you get an error after specifying an address in the rcpt to line which isn't one of the domains hosted by the mail server.

First let's try an email from a remote machine to a known address:

$ telnet plpb.example.com smtp

Here's what you type:

ehlo plpb.example.com
mail from:<james@example.org>
rcpt to:<james@new.example.com>
data
Hi James

This is a test message, testing sending mail via unencrypted SMTP
from a remote machine to a known address on the SMTP server
without logging in.

James
.

Here's the output of the conversation:

220 plpb.example.com ESMTP Postfix (Debian/GNU)
ehlo plpb.example.com
250-plpb.example.com
250-PIPELINING
250-SIZE 30720000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
mail from:<james@example.org>
250 2.1.0 Ok
rcpt to:<james@new.example.com>
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
Hi James
This is a test message, testing sending mail via unencrypted SMTP
from a remote machine to a known address on the SMTP server
without logging in.

James
.
250 2.0.0 Ok: queued as 5F5743C8C2

The mail gets sent successfully.

From a Remote Machine to an Unknown Address

Now try from a remote machine to an unknown address:

$ telnet plpb.example.com smtp

Here's what you type:

ehlo plpb.example.com
mail from:<james@example.org>
rcpt to:<james@example.com>

You won't be able to get any further than this because you'll get a Relay access denied error.

Here's the output of the conversation:

ehlo plpb.example.com
250-plpb.example.com
250-PIPELINING
250-SIZE 30720000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
mail from:<james@example.org>
250 2.1.0 Ok
rcpt to:<james@example.com>
554 5.7.1 <james@example.com>: Relay access denied

This is correct behaviour and means your server is not an open relay. To be able to send emails to unknown addresses you need to login. Let's look at this next.

Understanding Authentication

To enable users who aren't running mail clients on the same machine as the SMTP server to send email you have to let them login. There are various different ways a user can send login information to the SMTP server including PLAIN and LOGIN. The same login mechanisms can be used on an encrypted or unencrypted connection so don't assume that just because you are logging into the server, that the connection is secure.

To see if the SMTP server you are connecting to supports authentication, and to find out what authentication it supports, you should look for this line in the output which is returned after you've sent the ehlo line:

250-AUTH PLAIN LOGIN

Some servers will also send this second line so that broken clients like Outlook Express 4 can understand that the server supports SMTP AUTH:

250-AUTH=PLAIN LOGIN

Either way, this tells you that the SMTP server supports authentication and that it supports the PLAIN and LOGIN authentication methods. Neither of these methods are secure unless you are using an encrypted connection. There are other methods too like CRAM-MD5 or DIGEST-MD5 which prevent someone listenting from viewing the password in plain text, but anyone listening in on the connection can simply send the same information to pretend to be the user so there is really very little benefit to them and lot's of servers don't use them. Instead if you want security between the mail client and the SMTP server you use an encrypted connection and in that case you can just send the username in plain text anyway because the connection is secure.

SASL

Behind the scenes, it is very likely that the SMTP server will use the Simple Authentication and Security Layer (SASL) to check the username and password (using whichever format they are supplied in). It is possible that an IMAP or POP3 server running for the same mailboxes will also use SASL for its authentication and that means users can share the same login details for all their mail services and it means sysadmins have less work to do managing the accounts. SASL isn't any sort of protocol the clients will use, it is just something that goes on behind the scenes on the mail server.

Enabling and Disabling Unencypted Authentication in Postfix

If you are using Postfix in the way described in my other articles SMTP authentication over an unencypted connection is disabled because it is not secure. For testing though you can allow it by running this command:

$ sudo postconf -e smtpd_tls_auth_only=no

and then restarting Postfix:

$ sudo /etc/init.d/postfix restart

Afterwards, set it back like this:

$ sudo postconf -e smtpd_tls_auth_only=yes

Testing PLAIN Authenticated, Unencrypted SMTP

Note

If you are using my set up, the PLP A and PLP B servers do not support sending emails so this won't work on them, you'll just get one of these errors:

535 5.7.8 Error: authentication failed: authentication failure
535 5.7.8 Error: authentication failed: bad protocol / cancel

Instead you should test the maila server.

Using PLAIN authentication, the username and password have to be sent as a single string which is Base 64 encoded. The unencoded string looks like this with \0 characters at the start and between the username and password:

\0username\0yourpassword

It is common to use the email address itself as the username so this is what we'll do in these examples. You can generate the base64 version of the string using mmencode and use it like this without needing to escape any other characters:

$ echo -ne '\0james@new.example.com\0yourpassword' | mmencode
AGphbWVzQG5ldy5leGFtcGxlLmNvbQB5b3VycGFzc3dvcmQ=

If you don't have mmencode installed you can use openssl:

$ echo -ne '\0james@new.example.com\0yourpassword' | openssl enc -base64
AGphbWVzQG5ldy5leGFtcGxlLmNvbQB5b3VycGFzc3dvcmQ=

Or Perl, (with some escaping):

$ perl -MMIME::Base64 -e 'print encode_base64("\000james\@new.example.com\000yourpassword")'
AGphbWVzQG5ldy5leGFtcGxlLmNvbQB5b3VycGFzc3dvcmQ=

Tip

Just remember that just because the username and password are encoded, they are still easy for an eavesdropper to read. If you just change "encode_base64" to "decode_base64" in the perl example you'll see just how easy this is (the \0 characters aren't shown):

$ perl -MMIME::Base64 -e 'print decode_base64("AGphbWVzQG5ldy5leGFtcGxlLmNvbQB5b3VycGFzc3dvcmQ=");'
james@new.example.comyourpassword

Let's test PLAIN authentication. From a remote machine:

$ telnet maila.example.com smtp

Here's what you type, replacing the base 64 encoded string with the correct version for your username and password:

ehlo maila.example.com
AUTH PLAIN AGphbWVzQG5ldy5leGFtcGxlLmNvbQB5b3VycGFzc3dvcmQ=
mail from:<james@example.org>
rcpt to:<james@example.com>
data
Hi James

This is a test message, testing sending mail via unencrypted SMTP
from a remote machine using AUTH PLAIN to an unknown address.

James
.

Once again you must press Enter after the dot on its own line and you should test with an email address not on the local machine to check it will now send out emails if you are authenticated.

If the authentication information isn't correct you'll see this line:

535 5.7.8 Error: authentication failed:

If you have set up not to allow unencrypted signins you'll see this:

504 5.5.4 Encryption required for requested authentication mechanism

See the previouse section for how to enable/disable unencypted logins in Postfix. Otherwise you'll see:

235 2.7.0 Authentication successful

Here's the full conversation once you've authenticated correctly:

ehlo maila.example.com
220 maila.example.com ESMTP Postfix (Debian/GNU)
250-maila.example.com
250-PIPELINING
250-SIZE 30720000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH PLAIN AGphbWVzQG5ldy5leGFtcGxlLmNvbQB5b3VycGFzc3dvcmQ=
235 2.7.0 Authentication successful
mail from:<james@example.org>
250 2.1.0 Ok
rcpt to:<james@example.com>
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
Hi James

This is a test message, testing sending mail via unencrypted SMTP
from a remote machine using AUTH PLAIN to an unknown address.

James
.
250 2.0.0 Ok: queued as 14DC0471C

Testing LOGIN Authenticated, Unencrypted SMTP

LOGIN authentication happens in a very similar way but the username and password are sent separately. First let's base 64 encode the username and password:

$ echo -ne 'james@new.example.com' | openssl enc -base64
amFtZXNAbmV3LjNhaW1zLmNvbQ==
$ echo -ne 'yourpassword' | openssl enc -base64
cGFzc3dvcmQ=

Let's test it. Again, from a remote machine:

$ telent maila.example.com smtp

Here's what you type, replacing the base 64 encoded string with the correct version for your username and password:

ehlo maila.example.com
AUTH LOGIN
amFtZXNAbmV3LjNhaW1zLmNvbQ==
cGFzc3dvcmQ=
mail from:<james@example.org>
rcpt to:<james@example.com>
data
Hi James

This is a test message, testing sending mail via unencrypted SMTP
from a remote machine using AUTH LOGIN to an unknown address.

James
.

Here's the entire conversation:

ehlo maila.example.com
220 maila.example.com ESMTP Postfix (Debian/GNU)
250-maila.example.com
250-PIPELINING
250-SIZE 30720000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH LOGIN
334 VXNlcm5hbWU6
amFtZXNAbmV3LjNhaW1zLmNvbQ==
334 UGFzc3dvcmQ6
cGFzc3dvcmQ=
235 2.7.0 Authentication successful
mail from:<james@example.org>
250 2.1.0 Ok
rcpt to:<james@example.com>
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
Hi James

This is a test message, testing sending mail via unencrypted SMTP
from a remote machine using AUTH LOGIN to an unknown address.

James
.
250 2.0.0 Ok: queued as D9138471

At this point remember to turn unencrypted auth login off if you enabled it for the tests:

$ sudo postconf -e smtpd_tls_auth_only=yes
$ sudo /etc/init.d/postfix restart

Understanding Encryption

As well as having a plain text conversation like all the examples so far, it is possible to encrypt the converstation between the client and the SMTP server. Of course, this doesn't mean that the message it self is encrypted for the rest of its journey to the recipient, just that it is encrypted until it reaches the server.

There are three main ways to encrypt the conversation:

  • SSL
  • TLS
  • STARTTLS

Secure Sockets Layer (SSL) is the predecessor of Transport Layer Security (TLS) so we won't consider it further. TLS is a cryptographic protocol that provide security and data integrity for communications over a network. Using TLS, every part of the SMTP conversation is encrypted. The one problem with this is that clients which don't support TLS won't understand any part of the conversation and won't be able to drop down to a less secure method if it is allowed. To solve this problem the STARTTLS command was introduced. This allows a client to issue the ehlo command in plain text and then use a secure connection from then on if both the client and the server support it.

Checking if a server supports TLS

To check if a server supports TLS you need to look at the output after the ehlo command. If it conatins this line then TLS is supported:

250-STARTTLS

Connecting to Different Configurations of SMTP Server

You can configure your SMTP servers in a number of different ways:

  • Unencrypted
  • SSL only
  • TLS only
  • Unencrypted initially then TLS via the STARTTLS command

Most people would use the last option but with that in mind you'll need to know the different ways you can connect to the different types of SMTP service.

On Postfix, this is configured by specifying smtpd_tls_security_level = may. There is more information on Postfix TLS here.

Connecting to a Server using Encryption

To connect to a non-secured SMTP server you would use this command as we have been doing so far:

$ telnet maila.example.com smtp

To connect to a server which should support TLS you can use the -starttls smtp option of openssl s_client to connect. This makes openssl connect normally (without encryption), send a STARTTLS command, negotiate the SSL encryption, and then allow you to interact with the encrypted session.

Here's the command:

$ openssl s_client -starttls smtp -crlf -connect maila.example.com:25

For an SSL server where you connect to a different port number and have to establish an SSL connection before the SMTP conversation you use this command:

$ openssl s_client -crlf -connect maila.example.com:465

Everything that worked before should work with the two encryped methods except now, even if you have AUTH logins disabled for non-encrypted connections, you should be able to connect.

Let's try. Connect like this:

$ openssl s_client -starttls smtp -crlf -connect maila.example.com:25

Enter the following commands for PLAIN login:

ehlo maila.example.com
AUTH PLAIN AGphbWVzQG5ldy5leGFtcGxlLmNvbQB5b3VycGFzc3dvcmQ=
mail from:<james@example.org>
rcpt to:<james@example.com>
data
Hi James

This is a test message, testing sending mail via TLS
from a remote machine using AUTH PLAIN to an unknown address.

James
.

Here's the actual output including the exchange of certificates:

CONNECTED(00000003)
depth=0 /C=GB/ST=Some-State/L=London/O=Internet Widgits Pty Ltd/CN=maila.example.com
verify error:num=18:self signed certificate
verify return:1
depth=0 /C=GB/ST=Some-State/L=London/O=Internet Widgits Pty Ltd/CN=maila.example.com
verify return:1
---
Certificate chain
 0 s:/C=GB/ST=Some-State/L=London/O=Internet Widgits Pty Ltd/CN=maila.example.com
   i:/C=GB/ST=Some-State/L=London/O=Internet Widgits Pty Ltd/CN=maila.example.com
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEOTCCAyGgAwIBAgIJAJIjOLPDIOagMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV
BAYTAkdCMRMwEQYDVQQIEwpTb21lLVN0YXRlMQ8wDQYDVQQHEwZMb25kb24xITAf
BgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPbWFpbGEu
M2FpbXMuY29tMB4XDTA5MDUxNzIwMzQ1M1oXDTEwMDUxNzIwMzQ1M1owcDELMAkG
A1UEBhMCR0IxEzARBgNVBAgTClNvbWUtU3RhdGUxDzANBgNVBAcTBkxvbmRvbjEh
MB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRgwFgYDVQQDEw9tYWls
YS4zYWltcy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVy+XL
mASmNS1XAGHIz+ZpDZYCLIZeVpMySYxctcMBbfuM/LixEbQi0pBPHnb82vqK82bg
dp/CQNch/HzHm9w+2bImdiRq7HJX5T4re+709Ts4FXQetDcsGUBRXTicIydFzS5h
oOldK5o+gwQvA9LKbZAYuwkjXPcWWW5A+43FwnuU6i+42Ycc8NZWuz1VepSEArnS
NNJZjePQHakcj4BGza8GzVkT5suAPY/WAobzW49nDCmHs2cEBaAGIXdAnJKtz3YL
sn9hzcDKDNaf9yHIjHMgoVFFEKUDMvXwkCnXRoWZPcl2fBA60ZxCn5YjjjwT6bf7
Rx/RKwUcBI3mmbJ5AgMBAAGjgdUwgdIwHQYDVR0OBBYEFG7Ebxv/kXiwEnsHAuQm
XiyKk7WGMIGiBgNVHSMEgZowgZeAFG7Ebxv/kXiwEnsHAuQmXiyKk7WGoXSkcjBw
MQswCQYDVQQGEwJHQjETMBEGA1UECBMKU29tZS1TdGF0ZTEPMA0GA1UEBxMGTG9u
ZG9uMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGDAWBgNVBAMT
D21haWxhLjNhaW1zLmNvbYIJAJIjOLPDIOagMAwGA1UdEwQFMAMBAf8wDQYJKoZI
hvcNAQEFBQADggEBAEi9yk42XERQdnoSf6g1iSwD32flexx3M6xQvBj2IBRIfS1k
8q23docVdLLAT8O86bcPBAN6tTPhDbYUwfWdo/cEpyaRpEpX18r6LXETk4GsWVFM
VghjI4gTnNEuKGMWDvvafoLsGnUP8k31M6rvnPhQ62Zh/nsObRaLiLxUe7FQGHOM
pqJoMRorigWr9KUw9vBz9znuGEokXpBPQHWLlSIQQIRbVkni0Pol6LkcHg7pxY20
BpIdQQtxhCgEE1pZKECai1GAtBiDJq2XXlo+znzMwpI3008yBlRv+UZrGnmKnSsJ
wO430I0cPgbtQ6HL4i1HriSD8W28Q1G9sni6wwE=
-----END CERTIFICATE-----
subject=/C=GB/ST=Some-State/L=London/O=Internet Widgits Pty Ltd/CN=maila.example.com
issuer=/C=GB/ST=Some-State/L=London/O=Internet Widgits Pty Ltd/CN=maila.example.com
---
No client certificate CA names sent
---
SSL handshake has read 2037 bytes and written 351 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DHE-RSA-AES256-SHA
    Session-ID: CC8A68A907FA72CF875D9F91995BD1E1DA43F61A1C1760A3EE01516312455FE7
    Session-ID-ctx:
    Master-Key: FFE8EE71CA8370CCB3A8925859B709AADDB034CEBB0C45F45F4D019798E4A766C8EBBDDF0C59269C8023AB062C4D2E18
    Key-Arg   : None
    Start Time: 1243178088
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)
---
250 DSN
AUTH PLAIN AGphbWVzQG5ldy5leGFtcGxlLmNvbQB5b3VycGFzc3dvcmQ=
235 2.7.0 Authentication successful
mail from:<james@example.org>
250 2.1.0 Ok
rcpt to:<james@example.com>
250 2.1.5 Ok
data
354 End data with <CR><LF>.<CR><LF>
Hi James

This is a test message, testing sending mail via TLS
from a remote machine using AUTH PLAIN to an unknown address.

James
.
250 2.0.0 Ok: queued as 9E986471C

(view source)