Rate this page

Send an email using netcat

Tested with Exim on

Debian (Lenny, Squeeze)
Ubuntu (Hardy, Intrepid, Jaunty, Karmic, Lucid, Maverick, Natty, Oneiric, Precise, Quantal)


To send an electronic mail message via SMTP using only netcat (or a similar program such as Telnet)


Email messages are normally composed using a dedicated client program, however for testing purposes it is sometimes useful to interact more directly with the mail server. This is possible because the protocol used for sending mail (SMTP, the Simple Mail Transport Protocol) is text-based and the necessary commands can be typed from the keyboard.

The usual reason for doing this is to bypass any mail handling software situated between yourself and the mail server. This helps to localise the source of any problems and gives better visibility of error messages.


Suppose that you want to send a email with:

In the first instance the email should be sent via SMTP to a mail server named mail.example.org. (It is unimportant whether this is a smarthost, an intermediate gateway, or the final destination.)



The method described here has six steps:

  1. Establish a connection to the SMTP port of the mail server.
  2. Identify yourself to the mail server
  3. Specify a return address for the message
  4. Specify at least one recipient for the message
  5. Send the message data
  6. Terminate the connection

It is important to understand that SMTP does not concern itself with RFC 822 message headers such as From, To, Subject and Message-ID. These are merely part of the payload to be transferred, and do not necessarily reflect where the message has come from or where it should be sent to. The addresses normally used for routing are those specified during the SMTP transaction using the MAIL and RCPT commands. These are commonly referred to as the SMTP ‘envelope addresses’.

Responses from the mail server take the form of a reply code followed by a message. It is the reply code which is of primary importance, since their meanings are defined by the SMTP specification, whereas the messages may vary between mail servers.

Be aware that there are two variants of netcat in widespread use that are not fully compatible with each other. The difference relevant here is that the OpenBSD variant can be configured to send a carriage return (CR) followed by a linefeed (LF) at the end of each line, whereas the traditional variant only supports the default behaviour of sending a linefeed. Some mail servers will accept either of these conventions, but CRLF is the only line ending permitted by the SMTP specification so is the only one that all mail servers are required to accept. For this reason it is better to use the OpenBSD variant if it is available.

Establish a connection to the SMTP port of the mail server

A connection can be established using netcat by specifying the name of the mail server followed by the port number. For SMTP this should normally be TCP port 25:

nc -C mail.example.org 25

The -C option instructs the OpenBSD variant of netcat to send a carriage return (CR) followed by a linefeed (LF) at the end of each line. As noted above, the traditional variant of netcat lacks this option.

The corresponding command to establish a connection using Telnet would be:

telnet mail.example.org 25

Netcat is somewhat more transparent than Telnet, so is the recommended choice if the OpenBSD variant is available, but either program would suffice for the current task. You may be aware that Telnet sends a handshake to negotiate options such as the terminal type, but this happens only when connecting to a Telnet server on the standard port number so should not occur in this instance.

The mail server should respond with a greeting similar in form to the following:

220 mail.example.org ESMTP Exim 4.72 Thu, 20 Dec 2012 12:00:00 +0000

The first part of the response following the reply code should be the fully-qualified, canonical domain name of the mail server (if it has one). Most mail servers then provide further information such as the name and version of the server software, however this is not obligatory and there is no set format.

Identify yourself to the mail server

Before sending any messages you must identify yourself to the mail server. Since you are acting as an SMTP client, your identity takes the form of a domain name (not a full email address). It can be sent as the argument of a HELO command:

HELO example.com

The server should respond with reply code 250:

250 mail.example.org Hello test.example.com []

As noted above, the text of this response may vary between servers. Be aware that some servers resolve the specified domain name and compare the result with the remote IP address from which the connection was initiated. If they do not match then the server may decide to reject any messages that you send on the grounds that they look too much like spam.

Modern SMTP clients normally use the more recent EHLO command in place of HELO. You can do likewise if you wish: differences are that EHLO responds with a list of available SMTP extensions, but may not be recognised by very old mail servers.

Specify a return address for the message

SMTP requires that you specify a return address for the message for use if it bounces. This typically matches the address given by the From and/or Reply-To header within the message itself, but it is not required to.

In this instance the return address is bar@example.org. The server is informed using the SMTP MAIL command:

MAIL FROM:bar@example.org

The server should respond with reply code 250:

250 OK

Bounce messages often contain useful information for troubleshooting, so it is a good idea to provide a real email address here. The return path is likely to be rejected if it does not at least look like an email address.

Specify at least one recipient for the message

Similarly, at least one recipient must be specified. This typically matches an address given in a To, cc or bcc header within the message itself, but it is not required to.

In this instance the sole recipient is foo@example.com. The server is informed using the SMTP RCPT command:

RCPT TO:foo@example.com

The server should respond with reply code 250:

250 Accepted

If you want to test sending to multiple recipients then you can issue multiple RCPT commands. Be aware that most servers place restrictions on what mail they will relay in order to prevent abuse:

In the latter case the server should respond with an error, for example:

550 relay not permitted

Another type of response you might encounter is reply code 451:

451- is not yet authorized to deliver mail from
451 <bar@example.org> to <foo@example.com>. Please try later.

This typically indicates that the server uses greylisting to counter spam.

Send the message data

The message itself is sent using the DATA command. This is followed by the text of the message (headers and body), then ends with a terminator which consists of a single full stop character on a line of its own:

From: bar@example.org
To: foo@example.com
Subject: Test
Date: Thu, 20 Dec 2012 12:00:00 +0000


The server should respond with reply code 250:

250 OK id=1TkB8u-0004rV-5a

By responding in this manner the mail server accepts responsibility for the message and ought to deliver, forward or bounce it. Alternatively the server can refuse to accept the message (and thereby avoid the need to bounce) if it has already decided that the message should not be delivered.

The only headers required by RFC 2822 are Date and From. Even that requirement is not necessarily enforced: some mail servers will deliver messages that are completely empty (no headers or body) without complaint. For test purposes, however, it is probably best to use a more normal-looking message unless there is a particular set of conditions that you are attempting to simulate.

Terminate the connection

The connection can be terminated using the QUIT command:


Alternatively, you can forcibly close the connection by:

however the QUIT command is the cleaner method if you are able.


Using expect to drive netcat

Simply piping the required sequence of commands into netcat is unlikely to work because the SMTP commands and responses would not be properly interleaved. If you want to use the method above from a script then you will need to make use of a program such as expect. Here is an example:


set timeout 30
proc abort {} { exit 2 }

spawn nc -C mail.example.org 25
expect default abort "220 "
send "HELO example.com\r"
expect default abort "\n250 "
send "MAIL FROM:bar@example.org\r"
expect default abort "\n250 "
send "RCPT TO:foo@example.org\r"
expect default abort "\n250 "
send "DATA\r"
expect default abort "\n354 "
send "From: bar@example.org\r"
send "To: foo@example.com\r"
send "Subject: Test\r"
send "Date: Thu, 20 Dec 2012 12:00:00 +0000\r"
send "\r"
send "Testing\r"
send ".\r"
expect default abort "\n250 "
send "QUIT\r"

Further reading