One of the first things that a newcomer to PHP learns is how to send a
simple email: using the
- Unformatted text:
- With plain text emails, only the most rudimentary structure can be given to a message; there's no inherent way to insert a heading or a bullet-point list. If HTML were allowed in the email, for example, this formatting could be provided to the message.
- No attachments:
- Because the email is a single plain-text message, there is no way to provide additional documents or other files in the body of the message. A compromise is to place the files in question on the public Web, and provide links to the files, but this also compromises the security of the documents.
These problems are not just limitations of PHP's mailing routines: they are limitations of the email transport mechanism. In order to get around them, a devious scheme was standardised in the 1990s.
Multipurpose Internet Mail Extensions
The MIME standard was designed to work inside the existing email transport system; as such, it doesn't need any special connection methods, and no complicated networking is required on the part of the developer. Instead, MIME allows for multi-part messages by inserting all the parts into a plain-text email, and separating the parts by a boundary.
Structure: Basic boundaries
As can be seen in the example above, two hyphens precede all instances of the boundary, and one boundary forms the end of one part and the start of the next. The end of the last part is denoted by two hyphens after the boundary closing that part.
The basic structure outlined above allows for the separation of parts, but all it can provide is multiple plain-text messages combined into one. To allow for more complex information to be encoded, headers must be provided in association with each part.
An issue arises with the boundary structure: how is the email reading client to know which lines denote the boundary for a part, and which are simply part of the message? The client can be informed of which boundary is being used by providing a header for the message in total. Headers are often used to denote the originator of the message, the software version of the sending server, and other such information which may be pertinent to the client; the MIME boundary can be added to this.
Headers: MIME message boundary
Content-type header tells the email client what kind of
data is provided in the message; the text following
is known as a MIME type. The concept of MIME types has been extended for use
beyond email, and is now commonly provided by Web and file servers in response
to a request for data.
The MIME type provided with a chunk of data can be used to identify the
data in question. There are various classes of data that have MIME types
associated with them, and subdefinitions for each class. The class and subclass
of data are given in
major/minor format; a few examples are
|text||plain||text/plain||Plain text documents|
|text||csv||text/csv||Comma-separated data files|
|application||application/pdf||Portable Document Format (PDF)|
|application||zip||application/zip||PKZIP compressed archives|
|application||msword||application/msword||MS Word documents|
|Types with multiple components|
|multipart||form-data||multipart/form-data||Web forms with uploaded files|
|multipart||mixed||multipart/mixed||Messages with many types of component|
Table 1: Sample MIME types
As can be seen above, the
multipart/mixed MIME type tells the
email reader that each part of the message can be of a different type. Just as
with the message, each part can have a header and a body. Taking this into
account, a fuller MIME-compliant message can be built.
Multipart emails with headers
Attachments and Content Headers
We've seen how to put multiple types of message into one email, but this is not sufficient for attaching documents and other files to an email message. There are two major problems with inserting documents into an email:
- As can be seen above, files can be inserted into an email as a MIME part,
but they are not given a filename, and are not treated as attachments. This
problem is solved by inserting another header along with the part's
- An email message has to be readable in its entirety by any mailserver
that happens across it. Because mailservers may run in many places, under
many languages and character sets, a binary data file is not guaranteed to
make it to the destination intact: it has to be encoded into a more basic
character set, and the email client has to be told how to decode the
resultant email part. This is done with a third header, called
Content-disposition attached to a message part can be one
of two types:
inline, meaning this type is to be shown as part
of the email, and
attachment, which denotes a file attached for
download. If it's an
filename can be
provided as a parameter to the
Content-disposition header. Using
this header, we can make the CSV data file in the above example into an
Multipart emails with disposition
This takes care of the first problem with attaching files to an email, but the second remains: encoding the attachment into a transferable format. There are two major encoding methods allowed by the MIME standard:
quoted-printable: a discriminate encoding, which allows standard text through without encoding, but translates non-standard characters into their hexadecimal ordinal values;
base64: an indiscriminate encoding, which takes the whole stream of data as one number, and translates it a chunk at a time, three bytes translating into a 4-character block.
base64 encoding is generally easier to produce, since the
quoted-printable encoding requires specialised translation tables.
base64, the data is broken up into 48-byte "lines", and
encoded into 64-character lines before insertion into the email.
Once an encoding has been picked, it should be provided in the header for the message part, as shown in the below example.
Attaching a binary file in base64 encoding
Now we have all the pieces of the puzzle: the ability to create an email message with multiple parts, and a way to encode and attach files to the email. It's just a matter of implementation.
Using PHP to send MIME-compliant emails
With the information above, implementation is no issue. The only problem
presented is how to define the MIME type of an arbitrary attachment.
Fortunately, UNIX systems provide the
file command, which can
read any file and work out the MIME type of its contents. On a Windows server,
no such analogue exists, but it is possible to obtain
Microsoft Services for Unix, or UnxUtils.
A MIME-compliant email solution is provided below, making use of this tactic and the information presented in this article.
mimemail.php: Mail-building class for PHP
Example usage of mimemail
Download the script: mimemail.php
Imran Nazar <email@example.com>, 2008
Article dated: 10th Aug 2008