Send MIME mail in PHP

Source: Internet
Author: User
Tags array empty header variables sprintf trim unique id valid

Summary: Writing a mail system or mailing list program is a big branch of PHP application, while PHP provides a simple function for sending emails, in practice it involves sending mail with attachments, testing the validity of the email address that the user has entered, especially if it is necessary to describe it in a specific section.

What is MIME?

MIME represents the Multipurpose Internet Mail Expansion protocol. MIME expands the basic text-oriented Internet mail system so that binary attachments can be included in the message.

RFC822 the content of the message body with a little restriction: only simple ASCII text can be used. As a result, MIME information consists of normal Internet text messages, and text messages have special RFC822 headers and formatted information bodies (attachments that are represented by a subset of ASCII). These MIME headers give a special way to represent attachments in a message.

What does the MIME information contain?

An ordinary text message contains a header part (To:From:Subject: Et cetera) and a body part (Hello Mr., etc.). In a MIME-compliant message, each part of the message is called a MIME segment, and each paragraph is decorated with a special header. MIME messages are only an extension based on RFC 822 messages. However, it has its own set of RFC specifications.

Header field

The MIME header is roughly divided into MIME headers and MIME segment headers, depending on the position in the mail package, and the MIME header refers to the entire message header, while the MIME segment header is only the header of each MIME segment.

The MIME headers are:

This header provides the version number of the MIME used. This value is customarily 1.0.

It defines the type of data so that data can be properly processed. Valid types are: Text,image, Audio,video,applications,multipart and message. Note that any binary attachment should be called Application/octet-stream. Some use cases for this head are: image/jpg, application/mswork,multipart/mixed.

It describes how the data is encoded, and is used by customer/mua to decode the attachment. For each attachment, you can use one of the encoding methods in 7bit,8bit,binary, Quoted-printable,base64, and custom. 7bit encoding is a common encoding used on the US ASCII character set. 8bit and binary codes are generally not used. For readable standard text, you can use quoted printable if you want to protect a gateway that has an impact on the format. Base64 is a common method that provides a no-brainer choice when it comes to deciding which encoding method to use; it is usually used in binary, not text data. Note that any non-7bit data must be encoded in a pattern so that it can pass through an Internet mail gateway.

If Content-type is Message/external-body or multipart/alternative, this head is useful.

This is an optional header. It is a free text description of the content of any information section. Description must use US-ASCII code.

This is an experimental header that is used to provide a hint to the client program/mua whether to display the attachment or as a separate attachment in the row.
The MIME segment header (the header that appears in the actual MIME attachment section) can have any of the above header fields in addition to the mime-version header. If a MIME header is part of an information block, it acts on the entire body of information. For example, if content-transfer-encoding is displayed in the information (the entire information) header, it applies to the entire body of information, but if it is displayed in a MIME segment, it is "only" used in that segment.

How do I create MIME-compliant information?

The simplest MIME information

There is no paragraph in this information, that is, no attachments. But it has the necessary head.

To: ' Alex (the Great) ' [>]
Hello Alexander,
How ' s bucephalus doing?

This is simply a RFC-822 message (text message) with a MIME header. Note that the Content-type header defaults to content-type:text/plain;charset= ' Us-ascii '.

The following is a more complex example:

From: ' Alex (The Great) '
Name= ' buce.jpg '
Content-description:take a look at him yourself

<......BASE64 encoded JPG image of Bucephalus ... >

What if you want to send multiple attachments and the type is not uniform? This is the "multi-part information" We are going to discuss.

Multi-part information (Multipart Messages)

This concept allows multiple items to be sent in a single message. For example, suppose Alexander wants to send a photo of his horse, along with a family Atlas of horses and a wonderful description. Such a simple requirement does not have the concept of multiple messages to be satisfied. In this case, we created a package that uses the Content-type header to support different parts of the message so that the recipient gets a picture, family map, and a wonderful description.

The Content-type header now has a value of "multipart", which means that it is a complete message message and that the header encapsulates only information. It also has a subtype of "mixed" (for example, pictures and text files are different types).

Let's take a look at:

From: ' Alex (The Great) '
boundary= "xx-1234ded00099a";

This is a MIME encoded message

Content-type:text/plain; Charset=us-ascii


Attached you'll find my horse, Bucephalus ', pedigree chart and photo


Name= "Buce.jpg";
Content-description: "A photo of Bucephalus"

<.....BASE64 encoded JPG image of Bucephalus ... >

Name= "Pedigree.doc"
Content-description: "Pedigree Chart of the Great horse"

<.....BASE64 encoded doc (pedigree.doc) of Bucephalus ... >
Let's take a look at the meaning of each of these parts:
1), the content-transfer-encoding in the MIME information header, is "7bit". Because Content-type is multipart/mixed, encoding should be one of 7bit,8bit or binary, 7bit is a widely used format.
2), like such a piece of information contains a variety of information. How does a client program know the difference between a JPG picture, a document, and an ordinary text? There is a boundary= "xx-1234ded00099a" parameter behind the Content-type. This value is used to separate the different parts of the message. It is called a MIME boundary tag. The value of the boundary tag must be as unique as possible to avoid confusion when the message range is exceeded.
3, "Warning" information ("This was a MIME encoded message") was there to allow MIME-compliant client programs to display it to the user, otherwise they would not understand what a blank email would mean.
4), now, back to the boundary marker. If you look at this simple message, you'll find the boundary tag (xx-1234ded00099a in every minute, that is, a boundary tag is used between each part, but each boundary tag starts with two connectors). It is important to note that at the end of the last MIME segment, the boundary tag does not just start with those two edges, but also ends with both of them. This must not be forgotten, because it defines the scope of the message.
5), let's take a look at the first two MIME segments:
The first paragraph is plain text information, so the Content-type is Text/plain, and the encoding is 7bit (we can also omit it because it will default if it is not indicated).
The second is a JPEG image. The corresponding representation is content-type:image/jpg. Name= "Buce.jpg" (which appears at the back of the Content-type, called parameters), indicates the name of the file, which is the name of the attachment that can be seen in the client program. If the name= "Buce.jpg" is not given, the Description field (if given) will be displayed as the name of the attachment.
6), note that JPEG images can be displayed in the mail, if the client can display the inline attachment. Alternatively, you can indicate to the client how you want to display the attachment. For example, if a content-disposition:attachment header exists, the JPEG image will be displayed as an attachment icon.

How do I create and implement a MIME message class?

Now let's create and implement a MIME message class in PHP. This MIME class must be able to:
1. Add Accessories
2. For each individual request, the attached data is encoded
3. Create MIME segment/Header
4. Generate a complete message containing MIME segments/headers
5. Return the entire message as a string
6, with the local mail processing program to send (or choose to invoke an SMTP mail handler)

This class is called Mime_mail.

Class Mime_mail {
var $to;
var $from;
var $subject;
var $body;
var $headers = "";
var $errstr = "";

var $base 64_func= '; If you do not specify the Base64 function to use PHP
var $qp _func = '; is empty at this time
var $mailer = ""; Make it the name of a valid mail object
? >

Here are some common variables (i.e., variables that can be manipulated directly in the script). Most of these variables are self explanatory. The $headers contains the optional header information that you want to send to the message handler. $ERRSTR is a variable that contains a readable error string that can be used in the calling script.

$base 64_func and $qp_func are "function processors" that users can customize. By default, they are set to an empty string. For $base64_func, an empty string means that we will use the PHP built-in Base64_encode () function. Quoted printable can be processed by $qp_func. There is no built-in quoted-printable encoding function in PHP (however, you can use Imap_qprint () If you have an IMAP installed.) In this article we will not discuss the Quoted_printable method.

var $mimeparts = array ();
? >

$mimeparts is an internal array that contains separate MIME segments in the message. Do not manipulate it and other private methods/variables outside of this class (or derived class).

function Mime_mail ($from = "", $to = "", $subject = "", $body = "", $headers = "")
$this->to = $to;
$this->from = $from;
$this->subject = $subject;
$this->body = $body;
if (Is_array ($headers)) {
if (sizeof ($headers) >1) $headers =join (CRLF, $headers);
else $headers = $headers [0];
if ($from) {
$headers = Preg_replace ("!") From:?. +? [ ]? )!i ", ', $headers);
$this->headers = Chop ($headers);
$this->mimeparts[] = ""; Add position 0
? >

We have the constructor of the object, which uses the "from" and "to" mail addresses, subject and message body and headers as parameters. For the body part of the message, you can give a normal message that you will probably enter. The last parameter is an optional (user-defined) header. For example, x-mailer:mymailer_1.0. Note that $headers can be an array that contains the different headers that will be sent to the mail sender, or just a container for a particular header. You cannot send from: header in the $headers parameter, if it is found, this part will be automatically removed. You can use multiple headers as follows: Array ("x-mailer:mymailer_1.0", "").

The $mimeparts is created with an empty item (index 0), which we'll see later.

We divide the generation of MIME headers, the generation of MIME segment headers, and the generation of final mail messages into several modules. The implementation of the method comes directly from the MIME Foundation we encountered earlier.

function Attach ($data, $description = "", $contenttype = octet, $encoding = BASE64, $disp = ' ") {
if (empty ($data)) return 0;
if (Trim ($contenttype) = = ") $contenttype = octet;
if (Trim ($encoding) = = ") $encoding = BASE64;
if ($encoding = = BIT7) $emsg = $data;
ElseIf ($encoding = = QP) $emsg = $ $this->qp_func ($data);
ElseIf ($encoding = = BASE64) {
if (! $this->base64_func) $emsg = Base64_encode ($data);
else $emsg = $ $this->base64_func ($data);
$emsg = Chunk_split ($emsg);
Check if Content-type is Text/plain and if CharSet is not specified, append the default charset
if (Preg_match ("!^"). TEXT. "! I ", $contenttype) &&!preg_match ("!; Charset=!i ", $contenttype)) $contenttype. =";
Charset= ". CHARSET;
$msg = sprintf ("Content-type:%scontent-transfer-encoding:%s%s%s%s",
$contenttype. CRLF, $encoding. CRLF,
(($description) && (Body!= $description))? " Content-description: $description ". CRLF: ""),
($disp? " Content-disposition: $disp ". CRLF: ""),
CRLF. $emsg. CRLF);
body== $description? $this->mimeparts[0] = $msg: $this->mimeparts[]= $msg;
return sizeof ($this->mimeparts);
? >

Let's analyze This method carefully:

1, the parameters used in this method are:

The attached actual data ($DATA)
Data description corresponding to the content-description header ($description)
The data Content-type value to be used in the Content-type header ($contentype)
Encoded values used in content-transfer-encoding ($encoding)
The layout values used in the Content-disposition header $disp can be inline or attach, and two are constant
2, such as base64,text values, and so on, as constants are defined in the attached. def file.
3. Use the $encoding value to determine which encoding method is needed to encode the data. Valid values are BIT7 (or 7bit), QP or BASE64. This function also checks whether the user wants to use his or her own BASE64 or QP function. In writing this article, only BIT7 and BASE64 are implemented in our class, however, you can pass your own quoted-printable function to use, through the $qp_func class variables discussed earlier.
4, after the encoding processing, you can note that the encoded information used Chunk_split (). This function splits the string into small segments based on the optional length. Because we do not point to length, the default length uses 76.
5, then, if the $contenttype parameter contains Text/plain, you must give the value of the "charset=" parameter. Its default value is defined in the constant charset, and the value is us-ascii. Note that when the head is passed with the parameter value, there must be a semicolon between the header and the argument ";".
For example, Content-type:text/plain; Charset=us-ascii
6. If the respective values of the other MIME segment headers are passed to this method, the segment headers are created. After all, we don't want to have a content-description head without a description. After these headers are created, we append the encoded data portion of the information. (Check the sprintf () statement in the method). Also, note that we use a special description field called Body (which is also a constant). This is what we use in the class implementation. If the Description field is the same as the body, we assign it to the first element in the $mimeheaders array. Please read it a few more times for this.
7, attach () returns the current size of the $mimeparts array, used in a reference to the calling script. This way you can tell which index an attachment "X" exists (the actual return value is 1 smaller than the index in the array)
8. Note that all headers must end with a CRLF () sequence.

Next, we look at the Fattach () method, Fattach () is similar to attach (), but it uses a filename as its first argument (as a replacement for $data in Attach ()). This method is only an encapsulation so that callers can invoke Fattach with a single file. Fattach () then reads the file and then calls attach () to append the data. This method returns 0 in the case of a failure and can be found in the $ERRSTR variable or, when successful, the index number of the file attachment in the $mimeparts array.

We have now developed the ability to append data, encode them, and place separate MIME segments in a private array. The work to be done is:

*. Complete the various segments of the MIME

*. Creates a message header that contains a MIME header, the message's original message header (such as to:, from:, and so on) and includes any user-defined headers. Append the full MIME segment to the header so that a complete mail package is generated.

The next approach we'll examine is, build_message (), which is invoked through a gen_email () method. Please note that build_message () is a private method.

function Build_message () {
Scenario 1: There is an attachment list, so the MIME header must be multipart/mixed
if (Is_array ($this->mimeparts) && ($nparts > 1)) {
If there is a mimie segment, the message body also becomes an attachment
if (!empty ($this->body)) {
$this->attach ($this->body, Body, TEXT, BIT7);

Create each MIME segment of a message now
for ($i =0; $i $nparts; $i + +) {
if (!empty ($this->mimeparts[$i]))
$msg. = CRLF. '--$boundary. CRLF. $this->mimeparts[$i]. CRLF;
$msg. = '-$boundary. '-'. CRLF;
$msg = $c _ver. $c _type. $c _enc. $c _desc. $warning $msg;
} else {
return $msg;
? >

1, we know that each MIME segment has a boundary tag, this tag has a unique ID. The boundary mark is used in:

In the MIME header, which indicates where the attachment must be divided

MIME segment; The bounds of the attachment are actually used before and after each paragraph (remember: The last boundary mark ends with two connectors (-) to indicate the end of the range). The $boundary contains a boundary tag, and it is unique by a random number and then MD5 hash generated. In addition, we give $boundary a "PM?" The prefix, here "?" is a random letter. An example of a boundary is "PMK------2345ee5de0052eba4daf47287953d37e" (PM means php MIME, so you can change it to your possible initial value).

2. In the process of generating MIME headers, we must consider two situations. These situations affect how the original message body of the message ($body in the constructor) is viewed and the special representation of the MIME header. The 1 is: There are many attachments that can be included. In this case, note that the part of the information is placed on the warning string "This is a MIME encoding message". Therefore, the real message body itself must be added to the information in the form of an attachment! The text of the message is usually the first attachment in the attachment list, which is $mimeparts in our example. This is exactly why we want to occupy a $mimeparts index so that the first index (0) can be used in the Message text section. The message body must be attached with a 7bit encoding.

if (!empty ($this->body)) {
$this->attach ($this->body, Body, TEXT, BIT7);
? >

A small piece of code above completes the work of attaching the text portion of the message as a MIME attachment. Notice that we use the ' body ' constant to indicate where attach () is going to add the attachment.

The second scenario is when the attachment does not exist, in which case, if the message text is provided, it will be the only information contained in the local variable $msg, in which case the MIME header is not required. (However, in this case we should also only specify the mime-version head)

3, MIME information header (Mime-version,content-type, etc.). ) is created when there is an attachment. In order to create a message body with a MIME message header, first the MIME header is created. Each valid MIME segment is then processed repeatedly through the $mimeheaders array. This is where the boundary markings are actually used. Depending on the consistency of the rule, a MIME segment is prefixed with two connectors ('--'. $BOUNDARY. Crlf) and, after the last MIME segment, appends two connectors after the boundary identifier to indicate that the message range ends.

4, the complete information in the variable $msg is returned as the value of this method.

Next method, Get_email () completes the generation of MIME messages through the Build_message () method. Since Build_message () is an internal method, Get_email () creates an RFC 822 header and appends MIME information after the Build_message () is called.

function Gen_email ($force =false) {
if (!empty ($this->email) &&! $force) return $this->email; Saves processing
$email = "";
if (Empty ($this->subject)) $this->subject = Nosubject;
if (!empty ($this->from)) $email. = ' from: '. $this->from. CRLF;
if (!empty ($this->headers)) $email. = $this->headers. CRLF;
$email. = $this->build_message ();
$this->email = $email;
return $this->email;
? >

For an instance of our class, the members of the class $email have the entire message information generated. To avoid unnecessary regeneration of the information, this method continues to create the headers and calls Build_message () only if $mail is empty. However, you can force a reprocessing by calling Gen_email (). (If the "to" information is changed or a new attachment is added, the caller appears to want to do so).

Gen_email () Creates a more familiar from header. In addition, if you do not specify a theme, it sets the theme to the default value (no Subject). We didn't keep the contents of the to and subject until later. This method returns the complete message information, which ends the task of creating MIME information.

The other two methods worth describing are print_mail () and Send_mail (), and all two use $force parameters. Print_mail () outputs the entire message information, Send_mail () uses the PHP mail () function to send the message. Optionally, Send_mail () uses an SMTP object and its Send method (specified by the user) to send the message.

How to test the validity of email?

General we often want to visit their own website friends can leave email, but many people will casually dozen, causing the trouble of the administrator, the following class can be online to check whether the email is valid (exist)

Function Verifyrule ($email);
Function Verifyonline ($email);

function Verify ($email, $type =0) {
if ($type ==0) return $this->verifyrule ($email); Check email syntax for 0 only
else return $this->verifyonline ($email); Otherwise, check online.

The basic idea is:

First check whether the standard email syntax, if met, get the user input email host information, using the GETMXRR () function to change the host DNS MX field, and then further check the input email exists.


$input =new Cemail;
/Check grammar
if ($input->verify ("", 0)) echo "valid";
else echo "Invalid";

Check online to see if the message is really there
if ($m->verify ("", 1)) echo "valid";
else echo "Invalid";

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.