SMTP is truely a simple mail transfer protocol. It is designed to transfer text to mail servers, which relay the message until it reaches the mailbox of the recipient. SMTP doesn't concern itself with mailbox and user management, that's where other protocols and their implementations come in.
Because SMTP is so straightforward, it is relatively easy to telnet an SMTP server and instruct it, by hand, to send an email. Here are two examples :
Consequently, it's pretty simple to create a mailer script that sends these SMTP commands and a mail message of choice to an arbitrary mail server.
There exist programs that do something similar and can be used to send automatic emails from scripts (e.g. to send log files, alerts, or the output of a command) : mail, mailx, .... on Linux, bmail for Windows, ...
An email consists of two parts : The envelope, and the message. The envelope shows the sender and recipient(s), which corresponds to the MAIL FROM and RCPT TO commands. During transport, SMTP servers may add additional information, such as a "Received From:" line. The envelope usually shows up as "Email Headers" in the receiving mail client program.
The message itself is plain text. Sender and Receiver may be repeated (in analogy to a letter). You can also create CC: and BCC: recipients here; you need to create corresponding RCPT commands to get them delivered.
A Subject: line followed by a whiteline marks the end of this section.
All of this is optional. The information contained in this part of the message is usually added to the "headers", some or all of which will be displayed by the receiving mail client.
The second part of the message is the actual body : the information you want to transfer. It can also be the only part of the message, that is, if you leave out the additional headers (cc:, subject, ...). So the message itself can consist of 1 ot 2 parts : optional headers + the actual body.
The end of the message is marked with a single . on a line by its own. This is actually a command to tell the SMTP server that DATA input has ended.
SMTP commands and message requirements are presented in RFC 2821.
Email is originally a strictly text medium, so mailing anything but plain text is a problem, because SMTP originally had no mechanism for this. That has changed with the development of MIME and SMTP servers that can handle it, but it requires some work to force a binary file through a text-only channel.
To include an attachment in your mail message, you need to split it in multiple parts, e.g. a text part and a part to hold your attachment. This is done by adding a "Content-Type: multi-part" to the message headers. You need to define a boundary, consisting of a string of alpha-numeric characters, that you will use to separate the parts of your message. You also need to declare the MIME version in the message header.
The message you create will look then something like this:
From: <Anonumous.Coward@anonymous.com>
To: <HotChick69@hotmail.com>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="000SomeRandomString000"
Subject: Hi there
--000SomeRandomString000
[text message goes here]
--000SomeRandomString000
[attachment goes here]
--000SomeRandomString000--
Note that the receiving mail client will interpret this and come up with a reasonable representation (such as hide the headers and boundaries).
Although we can now divide the mail message in multiple parts, we can still only send text. To send an attachment, it needs to be encoded as text, in such a manner that the receiving end can decode it and reconstruct the attached file.
To send an encoded attachments in a mail message, you need to declare a new content type (application/octet-stream, i.e a binary file intended to be read with the appropriate application), and the Content-Transfer-Encoding (the applied encoding, required for transfer through a text channel) in the applicable part of the message. This may look something like this:
From: <Anonymous.Coward@anonymous.com> To: <HotChick69@hotmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="000SomeRandomString000" Subject: Hi there --000SomeRandomString000 Here's a picture of me --000SomeRandomString000 Content-transfer-encoding: base64; Content-Type: application/octet-stream; name="PictureOfMe.png" iVBORw0KGgoAAAUhEUgAAAesAAADGBAMAAALXOAAAAIVBVEX////19fXIyMiW jIyCHh4AAAD/AAC377cA4AAAAP9gUeS1AAAX1ElEQVR4e1dTW8jOZLVwY1J9E [ ... ] eY484f== --000SomeRandomString000--
To encode a binary file to text, you can use a program such as mimencode (on Linux). It defaults to base64 encoding to produce 7-bit ASCII text out of any file you feed it.
Note that in a multi-part message, the blank lines are significant, they're part of the boundaries. Note also the leading dashes (--) for bouncaries, and leading and trailing dashes for the final boundary.
It's feasable to create a rudimentary mailer script to send email with attachments.
Multpart messages and MIME encoding is also used to create rtf or html messages (in stead of plain text), multiple versions of the same message, digests of multiple messages, and all kinds of other stuff. These applications, and a description of the message and body structure, are discussed in RFC 2045. Wikipedia also has an excellent entry on MIME.