smtp-cli — command line SMTP client

smtp-cli is a powerful SMTP command line client with a support for advanced features, such as STARTTLS, SMTP-AUTH, or IPv6 and with a scriptable message composition capabilities supporting anything from simple plain-text messages right up to building complex HTML emails with alternative plain-text part, attachments and inline images. The MIME-Type of the attachments can either be guessed automatically or alternatively set on the command line, separately for each attachment if required.

It's also a convenient tool for testing and debugging SMTP servers' setups. Even the hardcore mail admins used to typing the SMTP protocol over telnet need a specialised tool when it comes to verifying encryption settings of their TLS enabled server with a subsequent user authentication. Such things are pretty hard to type into a telnet session by hand :-)

The name smtp-cli stands for:

  1. smtp-client
  2. smtp-command line interface

Use the script for checking given server's capabilities, test you server's setup or create and send mails. Command line interface is intuitive, everything is scriptable and can run in a completely non-interactive mode from various scripts or cron jobs. It is also ideal for shipping log files from remote machines, running periodical mail delivery test loops, etc. Also if you ever needed to send a complex email with attachments from a command line, this script is all you need.

Releases
Download the latest version
Optional dependencies

Some features of smtp-cli are optional and available only when the appropriate perl modules are installed:

Users of other Linux distributions will have to find the appropriate packages by themselves, or install the modules directly from CPAN.

Make it executable
$ chmod +x smtp-cli
Test on your localhost:
$ ./smtp-cli --verbose --host=localhost
[220] 'server.domain.top ESMTP Postfix'
> EHLO localhost
[250] 'server.domain.top'
[250] 'PIPELINING'
[250] 'SIZE 20480000'
[250] 'ETRN'
[250] '8BITMIME'
> QUIT
[221] 'Bye'
Send an e-mail through a host which requires authentication after an encryption takes place:
 ./smtp-cli --verbose --host=relayhost.domain.top --enable-auth --user test \
--from test@domain.com --to user@another.domain.org --data message-body.txt
[220] 'server.domain.top ESMTP Postfix'
> EHLO localhost
[250] 'server.domain.top'
[250] 'PIPELINING'
[250] 'SIZE 10240000'
[250] 'VRFY'
[250] 'ETRN'
[250] 'STARTTLS'
[250] 'XVERP'
[250] '8BITMIME'
Starting TLS...
> STARTTLS
[220] 'Ready to start TLS'
Using cipher: EDH-RSA-DES-CBC3-SHA
Subject Name: /C=XX/CN=server.domain.top/Email=info@domain.top
Issuer  Name: /C=XX/CN=Domain.TOP Root CA/Email=ca@domain.top
> EHLO localhost
[250] 'server.domain.top'
[250] 'PIPELINING'
[250] 'SIZE 10240000'
[250] 'VRFY'
[250] 'ETRN'
[250] 'AUTH PLAIN LOGIN DIGEST-MD5 CRAM-MD5'
[250] 'AUTH=PLAIN LOGIN DIGEST-MD5 CRAM-MD5'
[250] 'XVERP'
[250] '8BITMIME'
AUTH method (PLAIN LOGIN DIGEST-MD5 CRAM-MD5): using CRAM-MD5
> AUTH CRAM-MD5
[334] 'PDE0OTQyOTcxOC4yNjAwOTYwQHNlcnZlci5kb21haW4udG9wPg=='
> dGVzdCBmOTUyY2RkM2VlODBiMzk1YjYxNDI4NjBlYzg2Y2ExZnJvb3Q=
[235] 'Authentication successful'
Authentication of test@localhost succeeded
> MAIL FROM: <test@domain.com>
[250] 'Ok'
> RCPT TO: <user@another.domain.org>
[250] 'Ok'
> DATA
[354] 'End data with <CR><LF>.<CR><LF>'
[250] 'Ok: queued as C5C3A299D7'
> QUIT
[221] 'Bye'
Compose a plain text email with attachments

For composing emails you're gonna need an optional MIME::Lite perl module. See the download section above for details.

./smtp-cli --from test@domain.com --to user@another.domain.org \
                 --subject "Simple test with attachments" \
		 --body-plain "Log files are attached." \
                 --attach /var/log/some.log@text/plain \
		 --attach /var/log/other.log

Pretty self-explanatory, isn't it? Standard plain text email with attachments. The only interesting bit is the syntax used for enforcing MIME-Type of the second attachment. The syntax some.log@text/plain will make some.log attached as text/plain part, while the MIME-Type of other.log will be guessed by the script and eventually default to application/octet-stream.

Attachment as an email body
./smtp-cli --from test@domain.com --to user@another.domain.org \
                 --subject "Image as a mail body" \
                 --attach /path/to/tux.png

If there is only one text or image file to be sent, the file itself could be the message body. At the same time it will be accessible as an attachment with a file name for easy saving. Best to show a screenshot I guess...

There is no Text or HTML body part and the email is not multipart/mixed. All that is in the email is Tux the Penguin image. You can immediately see it in your mailer but also can easily save it with its provided name tux.png. The same way it works with text files (or files forced to be text/plain, to be precise).

Compose a multipart/alternative email with both HTML and Plain text part and inline images

Sending HTML emails is popular, especially among non-technical people. They like to change font colours, backgrounds, embed images and apply all sorts of other useless effects to their one short line of text. Indeed, me and you are more than happy with plain text and we both know that some mail readers can't even display colours and graphics at all (our office manager wouldn't believe!). And therefore it is a good practice for HTML messages to use multipart/alternative MIME format with both HTML and TEXT parts. In this example we're going to go wild and even embed an inlined image or two into the HTML part.

However first of all prepare the message body. Or bodies, actually. First one is body.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head></head>
<body bgcolor="#ffffff" text="#000000">
<div align="center">
Here comes embedded <font color="#006600"><b>Mr Tux</b></font><br>
<img src="cid:tux.png"><br>
<i>Nice, isn't it?</i><br>
<img src="cid:smiley.png"><br>
</div>
</body>
</html>

Note the <img> tags with cid:filename.xyz source — that's the way to refer inlined attachments from inside the message. We will obviously have to inline-attach tux.png and smiley.png to the message to make it work.

Anyway, the second body file is a plain text representation of the above, call it body.txt:

Here comes embedded Mr Tux
... actually it doesn't ... 
Not in a text-only mail reader.
Sorry

That's it. Here comes the magic command line that puts it all together:

./smtp-cli --from test@domain.com --to user@another.domain.org \
                 --subject "HTML with embedded image" \
		 --body-html body.html --body-plain body.txt \
		 --attach-inline tux.png --attach-inline smiley.png

And this is what we get:

Screenshot of inlined images

Donations

Have you found this script useful? Do you use it in production? Support its author by a PayPal or CreditCard donation.


 

Place for your feedback...
20th September 2007 at 15:58
Fix work with ssmtp(port 465)
Before:
$smtp-client.pl --port=465 -host=localhost --from=spam@rm-rf.kiev.ua --to=spam@rm-rf.kiev.ua --data=/etc/group --verbose=2
^C

After:
$smtp-client.pl --port=465 -host=localhost --from=spam@rm-rf.kiev.ua --to=spam@rm-rf.kiev.ua --data=/etc/group --verbose=2
Starting SSMTP...
Using cipher: AES256-SHA
Subject Name: /C=US/ST=Berkshire/L=Newbury/O=Magic, Inc/OU=Unknown/CN=localhost/emailAddress=spam@rm-rf.kiev.ua
Issuer Name: /C=US/ST=Berkshire/L=Newbury/O=Magic, Inc/OU=Unknown/CN=localhost/emailAddress=spam@rm-rf.kiev.ua
[220] 'localhost ESMTP Exim 4.58'
> EHLO localhost
[250] 'localhost Hello localhost [127.0.0.1]'
[250] 'SIZE 20971520'
[250] '8BITMIME'
[250] 'PIPELINING'
[250] 'AUTH PLAIN LOGIN'
[250] 'HELP'
> MAIL FROM:
[250] 'OK'
> RCPT TO:
[250] 'Accepted'
> DATA
[354] 'Enter message, ending with "." on a line by itself'
[250] 'OK id=1IYMMq-000MLG-C2'
> QUIT
[221] 'localhost closing connection'

patch:
Index: smtp-client.pl
@@ -110,12 +110,18 @@
my (%features);

# Wait for the welcome message of the server.
-($code, $text) = &get_line ($sock);
-die ("Unknown welcome string: '$code $text'\n") if ($code != 220);
-$ehlo_ok-- if ($text !~ /ESMTP/);
+if ($port != 465)
+{
+ ($code, $text) = &get_line ($sock);
+ die ("Unknown welcome string: '$code $text'\n") if ($code != 220);
+ $ehlo_ok-- if ($text !~ /ESMTP/);
+};

# Send EHLO
-&say_hello ($sock, $ehlo_ok, $hello_host, \%features) or exit (1);
+if ($port != 465)
+{
+ &say_hello ($sock, $ehlo_ok, $hello_host, \%features) or exit (1);
+};

# Run the SMTP session
&run_smtp ();
@@ -131,18 +137,22 @@
sub run_smtp
{
# See if we could start encryption
- if ((defined ($features{'STARTTLS'}) || defined ($features{'TLS'})) && $starttls_ok)
+ if ((defined ($features{'STARTTLS'}) || defined ($features{'TLS'}) || $port == 465 ) && $starttl
{
- printf ("Starting TLS...\n") if ($verbose >= 1);
+ printf ("Starting TLS...\n") if ($verbose >= 1 && $port != 465);
+ printf ("Starting SSMTP...\n") if ($verbose >= 1 && $port == 465);

# Do Net::SSLeay initialization
Net::SSLeay::load_error_strings();
Net::SSLeay::SSLeay_add_ssl_algorithms();
Net::SSLeay::randomize();

- &send_line ($sock, "STARTTLS\n");
- ($code, $text) = &get_line ($sock);
- die ("Unknown STARTTLS response '$code'.\n") if ($code != 220);
+ if ($port != 465)
+ {
+ &send_line ($sock, "STARTTLS\n");
+ ($code, $text) = &get_line ($sock);
+ die ("Unknown STARTTLS response '$code'.\n") if ($code != 220);
+ };

if (! IO::Socket::SSL::socket_to_SSL($sock,
SSL_version => 'SSLv3 TLSv1'))
@@ -156,6 +166,14 @@
printf ("%s", $sock->dump_peer_certificate());
}

+ # Wait for the welcome message of the server (for sstmp).
+ if ($port == 465)
+ {
+ ($code, $text, $more) = &get_line ($sock);
+ die ("Unknown welcome string: '$code $text'\n") if ($code != 220);
+ $ehlo_ok-- if ($text !~ /ESMTP/);
+ };
+
# Send EHLO again (required by the SMTP standard).
&say_hello ($sock, $ehlo_ok, $hello_host, \%features) or return 0;
}
Mar 3   17:21 Looked for such a sw ever! (by Cornelinux)
Mar 9   16:42 Thanks, thanks, and once more thanks! (by Paolo Cravero)
Aug 1   16:26 Your Perl smtp script (by Jacob Smith)
Nov 23   16:20 GREAT! (by Daniel Siebert)
Jan 27   18:34 Problem with Hang at end of Data Command (by Dave Carey)
Mar 9   6:41 Nicely Done (by Caleb)
Mar 9   7:52 Re: Nicely Done (by Caleb)
May 6   13:22 Can i get Smtp-Server.pl (by Fadiebia)
May 9   1:24 Re: Can i get Smtp-Server.pl (by Michal Ludvig)
May 21   11:20 LF vs. CRLF (by Eberhard Mattes)
May 22   21:33 Re: LF vs. CRLF (by Michal Ludvig)
May 29   16:28 Re: Re: LF vs. CRLF (by Eberhard Mattes)
Jun 16   20:55 Re: Re: Re: LF vs. CRLF (by Edgard Pevidor)
Jul 8   19:43 Re: Re: Re: Re: LF vs. CRLF (by George)
Jul 8   19:50 Re: Re: Re: Re: LF vs. CRLF (by George)
Jun 21   15:27 Adding SUBJECT (by Carlos Ferriol)
Jun 21   22:44 Re: Adding SUBJECT (by Michal Ludvig)
Apr 3   18:39 Re: Re: Adding SUBJECT (by Mark Delahunty)
Apr 10   0:21 Re: Re: Re: Adding SUBJECT (by Michal)
Nov 15   11:30 qwerfty (by qwerfty)
Jul 20   22:30 Re: Re: Re: Adding SUBJECT (by MoH)
Sep 3   0:08 Unknown (by Unknown)
Nov 28   23:05 Subject not working (by Anyeos)
Jul 26   16:33 force_auth patch (by Ilya Evseev)
Jul 28   4:16 Re: force_auth patch (by Michal Ludvig)
Jul 26   16:36 bug: message should not contain zero timestamp (by Ilya Evseev)
Jul 28   4:26 Re: bug: message should not contain zero timestamp (by Michal Ludvig)
Sep 1   13:53 Not able to use the script with qmail MTA's (by Muthuvelu.T.J)
Sep 30   17:29 Re: Not able to use the script with qmail MTA's (by Todd Lucas)
Jan 18   16:28 HOW TO INPUT DATA FROM STDIN? (by Casco Bucci)
Dec 21   23:09 Re: HOW TO INPUT DATA FROM STDIN? (by Chris G)
Dec 21   23:17 Re: Re: HOW TO INPUT DATA FROM STDIN? (by Michal Ludvig)
Dec 22   0:29 Re: Re: Re: HOW TO INPUT DATA FROM STDIN? (by Chris G)
Mar 12   4:04 Command line SMTP client (by Donovan Berthoud)
Apr 5   14:57 bug: returncode to shell (by Paolo)
May 29   19:14 smtp-client.pl and smtp.gmail.com? (by Jiri Rosicky)
May 30   0:45 Re: smtp-client.pl and smtp.gmail.com? (by Michal Ludvig)
Jun 14   20:20 Re: Re: smtp-client.pl and smtp.gmail.com? (by Hans)
Jun 15   0:53 Re: Re: Re: smtp-client.pl and smtp.gmail.com? (by Michal Ludvig)
Oct 20   0:04 Re: Re: smtp-client.pl and smtp.gmail.com? (by Nahum Barnea)
Oct 20   21:59 Re: Re: Re: smtp-client.pl and smtp.gmail.com? (by Nahum Barnea)
Aug 16   1:37 Re: Re: Re: Re: smtp-client.pl and smtp.gmail.com? (by Lachlan Audas)
Aug 27   22:38 Re: Re: Re: Re: smtp-client.pl and smtp.gmail.com? (by Lachlan Audas)
Aug 5   6:07 Re: Re: smtp-client.pl and smtp.gmail.com? [SOLVED] (by Shantanu Gadgil)
Jul 18   6:34 Just GREAT dude! (by Daniel Gamez)
Jan 16   12:44 Good script (by Binh Nguyen)
Jun 1   0:40 awesome perl smtp client (by Cormander)
Jun 29   11:13 FR: Multiple "To:" field (by Roy Tam)
Dec 26   9:10 Re: FR: Multiple receiver (by eagle)
Jan 5   16:02 Re: FR: Multiple (by thushara wijeratna)
Sep 20   15:58 Fix work with ssmtp(port 465) (by Alex Kozlov)
Jul 4   1:42 magnificient (by NightKid)
Dec 3   2:38 hey hats off to the pl script (by vinayaka a)
Jan 8   7:48 Fine work - little correction necessary (by Josh)
Jan 21   9:06 Footer text (by Randy Monnin)
Mar 14   2:53 Re: Footer text (by Contact)
Apr 21   6:16 Great Script! (by Rajiv Durai Pandian)
May 7   5:07 Support for cc and bcc ? (by Damien Challet)
Sep 10   23:36 Re: Support for cc and bcc ? (by Ali)
Sep 23   6:19 Re: Re: Support for cc and bcc ? (by Arda)
Oct 15   5:46 Re: Re: Re: Support for cc and bcc ? (by Nizar)
Jun 23   10:31 Thanks, very nice (by Malcolm)
Jul 22   22:03 smtp-cli: Digest/HMAC_MD5.pm error (by Martin)
Jul 23   0:01 Re: smtp-cli: Digest/HMAC_MD5.pm error (by Michal)
Aug 5   15:36 nice script (by chris lo)
Aug 15   21:08 Great script! Extension for "--from" (by kalaha chaot)
Dec 14   12:57 Re: Great script! Extension for (by Ran)
Dec 17   21:27 Re: Re: Great script! Extension for (by Ran)
Aug 18   13:57 Socket Errors when trying to connect (by eellis)
Sep 1   14:33 smtp-cli (by Francois)
Dec 4   6:11 Load attacments from file (by joseph philbert)
Dec 28   19:49 Arm-Linux (by Rahul)
Apr 7   12:35 Fantastic software... $$$ on the way (by Arun)
Oct 7   11:19 Great little script (by Robin Patenall)
Dec 31   1:22 GOVNO EBANOE (by GOVNO EBANOE)
Jan 5   18:26 SMTP over SSL (by Nick)
Jan 6   0:32 Re: SMTP over SSL (by Michal)
Jan 11   2:00 Re: Re: SMTP over SSL (by Nick)
Mar 30   2:36 Header present inside mail body (by Massimiliano Ottimo)
Jun 8   18:45 Thanks just what I needed. (by Simon)