Email and SMTP basics

Dieser Post wurde aus meiner alten WordPress-Installation importiert. Sollte es Darstellungsprobleme, falsche Links oder fehlende Bilder geben, bitte einfach hier einen Kommentar hinterlassen. Danke.

Alex, a co-worker, asked me about sending emails today. He has to send out a mail from a development box which usually isn't allowed to send any emails to the outside world. This is archived by re-mapping the hostname of the company's SMTP-server to a dedicated internal IP providing an SMTP server without outbound abilities. I answered his questions but didn't have the time to explain the background. Here is it.


Ask someone what parts and email has and you'll likely get an answer like: "From", "To", "Subject" and "Text" which isn't wrong, but only a small part of the truth.

Every Email has only two parts: Header and body. The header contains all "meta" information about that mail like sender (from), recipient (to), subject and the date the mail was created. The body is what we know as the "mail text" but it may also include attachments or a HTML version of the text. Think of the whole email as one text file where a blank line separates header and body. You might want to open up a text editor now (like gedit for Ubuntu or notepad on windows) and build up your own email while reading this.

I'll ignore attachments and HTML emails for now because they don't change anything to the basics explained below. Google for MIME or ask CPAN to get more information about this.

Every header line contains a "field name" or "attribute key" followed by a colon (":"), one whitespace and the value for this attribute. A very basic mail header could be:

Subject: This is a mail.
In fact, this is a valid mail header and more than enough for a email to be delivered. Other valid header attributes include "Date" (the email creation date), "Received" (information added by a transit mailserver who processed this mail), "Cc" and "Bcc" (both for additional recipients). Many attributes may appear more than once and most are either not important for basics or self-explaining. Any non-standard custom header may be added using the "X-" prefix, like "X-Mailer" (often used for the mail client software and version number).

You might want to open your mail client and look for an option like "show full mail", "show all headers" or "show internet header lines". Thunderbird does this if you press Ctrl+U when looking at a mail. You'll notice that your mail has header lines and no additional magic.

The header must not contain any empty lines. The first empty line within an email separates the header from the body (while the body may contain any number of empty lines). The body is shown as it is to the user, there is no special syntax or anything like this, but try to avoid a single dot (".") as the only content of a line.

Transport (SMTP)

Emails are transferred from one server to another using the SMTP protocol. It's an old protocol like nearly every protocol used in the Internet is and it's very simple and text-based.

Think of the guy at a fast food restaurant, a SMTP dialog is nearly the same like you ordering junk food:

Fast food guy: "Hello, what would you like to order?"

You: "Hi, I'ld like to have menu number three."

Fast food guy: "With french fries?"

You: "Yes."

Fast food guy: "With Coke?"

You: "Sure, but only few icecubes, please."

...and so one.

It's pretty much the same for a SMTP dialog where a SMTP client (like another server or a mail client) is talking to a SMTP server:

Server:220 ESMTP Tue, 27 Dec 2011 22:43:29 +0100Client:EHLO Hello [982.773.823.400]Server:250-SIZE 209715200Server:250-PIPELININGServer:250-STARTTLSServer:250 HELPClient:MAIL FROM: <>Server:250 OKClient:RCPT TO: <>Server:250 AcceptedClient:DATAServer:354 Enter message, ending with "." on a line by itselfClient:From: blog.writer@mycompany.comClient:To: blog.writer@mycompany.comClient:Subject: TestmailClient:Client:This is a test mailClient:.Server:250 OK id=1RfeoK-0004hr-KgClient:QUITServer:221 closing connection
All server messages start with a three digit number which is a status or result code. SMTP clients use these numbers to identify success and error replies. Everything is done as a dialog, the server will never send a line itself.

The first line is a reply for the connection to the server, it starts with "220" and is the SMTP server's way to say "hello unknown client". The client is expected to be a nice client and also say "hello server, my name is..." by sending a "HELO" command followed by it's (host)name.The server is so proud of what he could do - he tells every client. This one could handle mails up to 200 MB (209.715.200 bytes) and has the PIPELINING extension. It may also talk secretly using the STARTTLS command to encrypt the reminder dialog, but we don't need anything of this.

The next client command is a "MAIL FROM:" command telling the server the senders email address. The SMTP protocol requires all email addresses within commands to be wrapped by < and >. The server is happy with this sender and replies with "250 OK".

Every mail has only one author, but may have multiple recipients. The server has to know them and this is what the "RCPT TO:" command is for. It may be given multiple times and the server might accept or deny every single recipient. This command tells the server where to send the mail, it ignores the mail header!

The "DATA" command tells the server that the mail content will follow now. The reply contains a notice: Send as many lines as you like, I wouldn't ever think of acknowledging every single line. Just tell me that you're finished by sending a single dot (".") on a blank line. The client just pushes the complete mail containing header and body and adds the dot-line as requested, this line doesn't go into the mail body.

The server is happy now: He knows everything required to process the mail. Every mail gets a server-specific transit id ("1RfeoK-0004hr-Kg" for this one), in case of any email problems: Add this id to the error report, it's usually also written down in the servers logfile and greatly speeds up searching for a single mail.

We're done, the client finally says "goodbye" to the server by sending a "QUIT" command and the well-behaved SMTP server replies with it's own "goodbye" style.

How to go one

You could talk SMTP to any server you like using a telnet client connecting to port 25 (the SMTP port) of a SMTP server or by using a TCP connection from within your program, but life is easier when using something line Net::SMTP. It takes care of the whole SMTP part for you, but knowing what happens during the SMTP dialog should make your life much easier when using Net::SMTP.

The initial problem's solution is easy: Understand SMTP and email syntax and use Net::SMTP to connect to an outside SMTP server. As long as SMTP connections are allowed by your companies firewall, you're done.


3 Kommentare. Schreib was dazu

  1. Nice writeup. Part of the confusion is that aside from email's header + body, there is also envelope information like envelope sender. This is not part of the email, but almost usually gets injected into the email header by the SMTP server (the Delivered header and sometimes others). So the two concepts get blurred.

  2. anonymous

    I'm missing links to the relevant RFCs so the interested reader can see how much details you glossed over. Seriously, I could reply "no, it's not" to every second sentence of the technical explanation. Email::Sender is the better choice for delivery compared to Net::SMTP. It provides even greater abstraction (allowing for testing/mocking and switching to local delivery in case of emergencies), provides secure transport mechanisms (TLS), handles protocol errors and network failures correctly (whereas in Net::SMTP the programmer must deal with that manually).

  3. Sebastian

    You're right, there are much easier usable modules. I didn't want to show a nice and easy way to send a email using Perl but how emails and SMTP work and Net::SMTP was a requirement for the job which made me write this article.

Schreib was dazu

Die folgenden HTML-Tags sind erlaubt:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>