Sending Emails with SMTP

After setting up an email server, one way to test it, is connecting directly to port 25 (SMTP) and talking to the server. Unlike in Simple dummy Mail Server for development in this post, we’ll only use telnet. Or we could also use netcat, also known as the “Swiss Army Knife” of network tools.

Which mailserver?

As first step, we need to figure out, which mail server is responsible for receiving emails for a specific domain. This is all available in DNS, the domain name system, in so-called MX records. Let’s assume, we want to send a email to the mailbox a.dangel at the domain gmx.de. Then we’ll lookup the MX record:

$ host -t MX gmx.de
gmx.de mail is handled by 10 mx00.emig.gmx.net.
gmx.de mail is handled by 10 mx01.emig.gmx.net.

So, there are two mail servers responsible, both have the same priority (10). Let’s just take the first one: mx00.emig.gmx.net.

Connecting to the mail server

We can now connect to the server via telnet on port 25 and start the SMTP communication. This will tell us, whether the mailbox exists:

$ telnet mx00.emig.gmx.net 25
Trying 212.227.15.9...
Connected to mx00.emig.gmx.net.
Escape character is '^]'.
554-gmx.net (mxgmx015) Nemesis ESMTP Service not available
554-No SMTP service
554-IP address is black listed.
554 For explanation visit http://postmaster.gmx.com/en/error-messages?ip=185.xx.xx.xx&c=bl
Connection closed by foreign host.

Oops, so GMX has a simple check implemented, which prevents dial-up, consumer lines from sending mails directly via SMTP. That’s a pity, but it helps preventing unsolicited messages (aka. spam). If the origin IP address belongs to an (dynamic) IP address space of an ISP, then GMX directly closes the connection. End-users are supposed to send emails via the port 587, as described in RFC 6409. And they should also use a different mail server for sending mails, such as mail.gmx.net for GMX. However, there we need to authenticate.

This blacklisting of end-user IP address space is also the reason, why you can’t run a mail server at home, which actually can take part of the public mail server system. You’re IP address will likely be blacklisted.

We can workaround this obstacle by spinning up a VM in the cloud and working from there. If you connect from your cloud VM, then the output looks like this:

$ telnet mx00.emig.gmx.net 25
Trying 212.227.15.9...
Connected to mx00.emig.gmx.net.
Escape character is '^]'.
220 gmx.net (mxgmx016) Nemesis ESMTP Service ready

Note: If the mail server doesn’t receive any commands within a timeout, it will automatically close the connection.

Mailbox existence check

Now we can do a first query: Does a specific mailbox exist? Here’s the complete command sequence:

$ telnet mx00.emig.gmx.net 25
Trying 212.227.15.9...
Connected to mx00.emig.gmx.net.
Escape character is '^]'.
220 gmx.net (mxgmx014) Nemesis ESMTP Service ready
HELO test
250 gmx.net Hello test [35.xx.xx.xx]
MAIL FROM:<>
250 Requested mail action okay, completed
RCPT TO:<a.dangel@gmx.de>
250 OK
QUIT
221 gmx.net Service closing transmission channel
Connection closed by foreign host.

First we need to greet: “HELO” tells the mail server, who we are. Usually the servers use the hostname or their domain name, for which they are providing emails. But most often, arbitrary names are possible. Some mail server check, whether the given name in the HELO command matches a DNS A record, and whether the PTR record of the IP address matches again the given name. That’s why you usually need to have a PTR record setup correctly for your (static) IP address.

Next, we start the sequence of delivering a email: With “MAIL FROM” we define the envelope origin email. If there is no email present, then we basically tell, we want to send a “bounce” mail - an error message, to which no response is wanted. If a bounce mail can’t be delivered, it won’t produce another error message, thus avoiding a flood of bounces.

Last step is the recipient email address, given with “RCPT TO”. If the mail server responds with “250 OK”, then we can be sure, that the mailbox is existing. Otherwise the mailserver would lie to use… since we checked with the MX record for the correct mail server, we are pretty sure now.

Finally, we are going to disconnect using the “QUIT” command.

If the mailbox doesn’t exist, the sequence would look like this:

RCPT TO:<not-existing-email-account-xyz@gmx.de>
550 Requested action not taken: mailbox unavailable

The server responds with code “550” now, telling us, that the “mailbox [is] unavailable”.

Sending a test email

When sending a mail via telnet, we need to do everything by ourselves, what usually is being done by the mail client. For instance, we need to fill the current date in the correct format as describe in RFC822. Luckily the date command line utility provides this easily:

$ date --rfc-822
Sat, 07 Oct 2017 09:23:11 +0000

We’ll take this date string later.

Here’s the session, to send a simple text message:

$ telnet mx00.emig.gmx.net 25
Trying 212.227.15.9...
Connected to mx00.emig.gmx.net.
Escape character is '^]'.
220 gmx.net (mxgmx015) Nemesis ESMTP Service ready
HELO test
250 gmx.net Hello test [35.156.242.254]
MAIL FROM:<>
250 Requested mail action okay, completed
RCPT TO:<a.dangel@gmx.de>
250 OK
DATA
354 Start mail input; end with <CRLF>.<CRLF>
Subject: test mail via telnet
To: a.dangel@gmx.de
Date: Sat, 07 Oct 2017 11:25:00 +0200

This is a simple text message.
.
250 Requested mail action okay, completed: id=1Mwgem-1d3pAz0lTO-00yAJq
QUIT
221 gmx.net Service closing transmission channel

Instead of quitting, we now continue the session with “DATA”. When transmitting a mail, we first need to provide the mail header (the mail client does this automatically). Usually we have a “Subject” header, we can have the “To” header (or “CC”). And the “Date” header. Without these headers, the message is more likely to be classified as spam.

The header is separated from the actual body by an empty line. After that, we can place as many text lines, we want to send. Note, that we didn’t specify the “Content-Type” header, so the mail is assumed to be a plain text message. Also note, that SMTP uses by default only the original 7-Bit ASCII code, which led to encodings like Quoted-printable.

If the text is complete, you’ll need to finish it with a line, the only contains a single dot. This is the marker, that the mail data is complete. After that, the mail server confirms the delivery with code “250”.

Anonymous or fake mails

With that information, we can now send slightly anonymous emails: Since we have full control about the (initial) header fields like “To” or “From”, we can use arbitrary contents. Note, that the mail server will still add the “Received” header lines, which can be used to trace back the email.

Let’s say, we want to send a mail, that looks like as it is from “anonymous@gmx.de”:

$ telnet mx00.emig.gmx.net 25
Trying 212.227.15.9...
Connected to mx00.emig.gmx.net.
Escape character is '^]'.
220 gmx.net (mxgmx017) Nemesis ESMTP Service ready
HELO test
250 gmx.net Hello test [35.156.242.254]
MAIL FROM:<>
250 Requested mail action okay, completed
RCPT TO:<a.dangel@gmx.de>
250 OK
DATA
354 Start mail input; end with <CRLF>.<CRLF>
Subject: test mail anonymous
From: anonymous@gmx.de
To: Undisclosed
Date: Sat, 07 Oct 2017 11:36:00 +0200

This is a simple text message, that should look like as it is from
anonymous.
.
250 Requested mail action okay, completed: id=1N3JoW-1dJHTG3EFW-010LIW
QUIT
221 gmx.net Service closing transmission channel
Connection closed by foreign host.

Note, that we now have defined the “From” header ourselves. Previously it was filled by the mail server automatically, and many other header fields will be added automatically by the server, if they are missing.

This is how many faked emails are created.

Cloud VM

Unfortunately, telnet mail sending to GMX is not possible directly after starting a fresh VM. See the session:

$ telnet mx00.emig.gmx.net 25
Trying 212.227.15.9...
Connected to mx00.emig.gmx.net.
Escape character is '^]'.
554-gmx.net (mxgmx014) Nemesis ESMTP Service not available
554-No SMTP service
554-Bad DNS PTR resource record.
554 For explanation visit http://postmaster.gmx.com/en/error-messages?ip=35.157.208.51&c=rdns
Connection closed by foreign host.

The IP address is “35.157.208.51” and it’s PTR record is

$ host 35.157.208.51
51.208.157.35.in-addr.arpa domain name pointer ec2-35-157-208-51.eu-central-1.compute.amazonaws.com.

GMX by default disallows this - even though the IP address could be static (depends on how long you can claim the IP address).

For Amazon AWS, there is this solution:

  • Request a Elastic IP. This IP, you can keep independently of the lifetime of a VM. You can assign this IP later to a different VM.
  • Request with this form a reverse DNS entry for the IP address. Note, that you need to have a forward A record setup for the domain, you want to have here. This means, you also need control over the domain, being able to configure the DNS entries.
Andreas Dangel | subscribe via RSS | adangel | .onion © Copyright 2019. adangel.org (30 June 2019)