Sending Emails, with netcat

Plaintext protocol for the win!

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

Information Circle
info

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.

Warning
warning

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# For plaintext connection
# This is OpenBSD Netcat here, GNU Netcat doesn't support LF to CRLF conversion (the -C argument)
$ nc -C mail.csclub.uwaterloo.ca 25
> 220 mail.csclub.uwaterloo.ca ESMTP Postfix

# For SSL
# ncat is bundled with Nmap, so make sure that Nmap is installed
# 465 is the port for SMTP with SSL/TLS
$ ncat -C --ssl mail.csclub.uwaterloo.ca 465
> 220 mail.csclub.uwaterloo.ca ESMTP Postfix

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.

Information Circle
info

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?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Say hello!
EHLO 127.0.0.1
> 250-mail.csclub.uwaterloo.ca
> 250-PIPELINING
> 250-SIZE 52428800
> 250-ETRN
> 250-AUTH PLAIN
> 250-AUTH=PLAIN
> 250-ENHANCEDSTATUSCODES
> 250-8BITMIME
> 250-DSN
> 250-SMTPUTF8
> 250 CHUNKING

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:

1
echo "$USERNAME:$PASSWORD" | base64

And now we feed the generated Base64 string into netcat.

1
2
3
4
5
6
# Tell the server we will be using PLAIN as authentication method
AUTH PLAIN
> 334
# Server says go ahead and we will go ahead and give our credential
[YOUR_COMBINED_BASE64_HERE]
> 235 2.7.0 Authentication successful

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:

1
2
3
4
5
6
7
8
9
# Tell the server which FROM address to use
MAIL FROM:<[email protected]>
> 250 2.1.0 Ok
# And who are the recipients.
# Note that there can be multiple RCPT TO commands to indicate multiple recipients
# The To, Cc and Bcc information is actually added in the DATA field,
# which we will be typing in shortly
RCPT TO:<[email protected]>
> 250 2.1.5 Ok

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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Tell the server we are now sending the data portion
DATA
> 354 End data with <CR><LF>.<CR><LF>
# Type in the mail headers and body
From: [Leo Shen] <[email protected]>
To: <[email protected]>
Date: Wed, 19 Jul 2023 23:16:48 -0400
Subject: Hello from netcat

This is an email composed with `ncat --ssl mail.csclub.uwaterloo.ca 465`.

.
> 250 2.0.0 Ok: queued as 108142E003A

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:

1
2
QUIT
> 221 2.0.0 Bye

Check the destination mailbox, and if everything goes okay, you've sent your Email with just netcat and your bare hands!


1

ESMTP (Extended Simple Mail Transfer Protocol), defined in RFC1869.

Published on Oct 30, 2023
JS
Arrow Up