Sending email might sound complicated—in fact it is. After years of spam fighting efforts, layers upon layers of complexity was added and Email has turned into the behemoth we are dealing with today, where most people and organization leave it to dedicated mail providers.
But that's a rant of another day. Most of the complicated black magic happens under the hood, after we have submitted our mail to the server. And the submission part, fortunately, stays pretty simple. The way you read your Email changed quite a bit (POP1 -> POP3 -> IMAP), but sending still uses SMTP, just like the 1980s. There has been extensions1, yes, but it remains to be plaintext and most of the commands remains. And since it's plaintext, let's open up netcat
and send an email with just that!
Choosing a netcat client
tl/dr Use ncat
bundled with Nmap
. If you don't need encryption (you really should though), OpenBSD's netcat would do.
Wait there's difference on which netcat version to use? Wait there're a trillion different implementations of netcat? Indeed and it's a pain to explain…
Basically there're two things we are looking for here: SSL support and use CRLF as newline character.
SSL support is self-explanatory: you want encryption to the server, and you should as password is sent via Base64 on SMTP, which a sniffer can easily reveal with a Base64 decoder if being sent via plaintext. Only Nmap
's version support SSL out of the box.
The CRLF shenanigan is more subtle: POSIX-compatible systems (so any UNIX, Linux, and all their derivatives) uses <LF>
as a line break character, while Windows and most of the communication protocols (stuff like HTTP, SMTP) uses <CR><LF>
instead. So when you hit Enter
on UNIX/Linux, you are sending <LF>
to the server to indicate newline, which is technically bad behavior. Most SMTP servers will simply ignore this by default and proceed to provide service, but some picky ones (namely Microsoft Exchange) might get mad. Since we are already pedantic enough to send Emails via netcat, let's make it right. Thus this leaves OpenBSD
's and Nmap
's implementation, both support convert all newline characters to <CR><LF>
.
Establish a connection
We will denote lines that are sent from the server with a >
in the front.
First we need to establish a connection to a mail server. I'm using one of the mail server that I maintain, University of Waterloo Computer Science Club's mail server as an example. If you are happy with sending your mail in plaintext, then any netcat implementation would do. If you want some semblance of modern Internet and want encrypted communication though, we will use TLS/SSL
to connect instead of STARTTLS
, as the latter requires TLS handshake after inputting a SMTP command and is difficult to do with just netcat.
Note that since password is transferred in Base64 on most SMTP servers, your username and password is NOT encrypted if you are using plaintext connection! SSL is strongly recommended, unless you are sitting right next to the mail server.
|
|
And the server greets us with a happy 220, means server ready!
Say Hello!
And now it's time to say hello. We do so by sending EHLO
with a hostname. The hostname is mostly used as a check when mails are sent between servers, so it's not relevant here. We will just send a loopback address.
But why is it called EHLO
rather than HELO
? Well actually both exists, but we will be using EHLO
since that indicates we will use ESMTP 1 which supports username and password login we will be using.
More specifically, it's SASL PLAIN
authentication mechanism we will be using. There actually exists LOGIN
authentication mechanism, which sounds more appropriate but has actually been deprecated in favor of PLAIN
. Confusing, right?
|
|
And the server tells us about its capabilities.
Login
Now we will provide the server with our credentials. Note that in SMTP, although the name says it's "plain auth", which may make you believe plaintext username and password are sent, they are actually combined into one string and get encoded with BASE64. To obtain the correct credential, use:
|
|
And now we feed the generated Base64 string into netcat
.
|
|
The server says we are good!
Finally, actually sending the mail
Now it's finally time to actually send the Email. First we tell the server where the mail is from and its destination:
|
|
And finally, the mail body. SMTP will just send whatever is before the termination symbol (<CR><LF>.<CR><LF>
here, just press Enter, followed by a dot, then another Enter) as the contents, and it doesn't care about it's plaintext or not. So to do attachments, you just concat the content of the file directly into the mail body, with some boundaries and metadata around it. But that's too complicated for a party trick with netcat, we will just send a plaintext mail here:
|
|
And the server tells us it has queued our mail in the send queue, just like a real world post office.
Now all's remaining is to Say Goodbye:
|
|
Check the destination mailbox, and if everything goes okay, you've sent your Email with just netcat and your bare hands!