The next method we will be examining,
build_message()
, does the bulk of all this work but is invoked via one gen_email()
method. Please note that build_message()
is a private method.
<?php
function build_message() {
$msg = "";
$boundary = 'PM'.chr(rand(65, 91)).'------'.md5(uniqid(rand())); # Boundary marker
$nparts = sizeof($this->mimeparts);
// Case 1: Attachment list is there. Therefore MIME Message header must have multipart/mixed
if (is_array($this->mimeparts) && ($nparts > 1)) {
$c_ver = "MIME-Version: 1.0".CRLF;
$c_type = 'Content-Type: multipart/mixed;'.CRLF."tboundary="$boundary"".CRLF;
$c_enc = "Content-Transfer-Encoding: ".BIT7.CRLF;
$c_desc = $c_desc?"Content-Description: $c_desc".CRLF:"";
$warning = CRLF.WARNING.CRLF.CRLF ;
// Since we are here, it means we do have attachments => body must become an attachment too.
if (!empty($this->body)) {
$this->attach($this->body, BODY, TEXT, BIT7);
}
// Now create the MIME parts of the email!
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 {
if (!empty($this->body)) $msg .= $this->body.CRLF.CRLF;
}
return $msg;
}
?>
This method is kind of a paradox, it is simple yet complex. Read on to see for yourself.
- We read earlier (under MIME Basics), that each MIME part has a boundary marker and that the marker is a unique id. The boundary marker is used in:
- the MIME Message header to denote where the attachments must be demarcated
- the MIME parts: actually before and after each part to delimit that attachment boundary. (Refer back to Alexander’s email with the image and pedigree chart!)
(Remember: The last boundary marker ends in two hyphens (–) to denote end of scope).
$boundary
contains the boundary marker and is the MD5 hash of the unique id of a random number. Additionally, we also prefix a “PM?” to$boundary
, where “?” is a random alphabet. An example value for$boundary
is"PMK------2345ee5de0052eba4daf47287953d37e"
(PM stands for PHP MIME, so you can change this to your initials may be!) - We must consider two cases during the process of generation MIME headers. These cases affect the way in which the original body of the mail (
$body
in the constructor) is treated and the very presence of MIME headers.- Case 1 is the reason why this article was written and you are reading it: There are attachments available to be included! In this case, please note that what would have been the body of the message is occupied by the warning string
"This is a MIME Encoded Message"
. Hence, the actual message body itself must be added as an attachment to this message! The email text usually is the first attachment in the list of attachments, which is$mimeparts[0]
in our case. That is precisely the reason why we bumped up an index in$mimeparts
so that the first slot (subscript 0) is available for the email text part. The email body must be attached as text/plain with 7bit encoding.
<?php
if (!empty($this->body)) {
$this->attach($this->body, BODY, TEXT, BIT7);
} ?>
The above snippet does this job of attaching the email text part as a MIME attachment. Note that we are using the ‘BODY’ constant to indicate to
attach()
where to attach it. - Case 1 is the reason why this article was written and you are reading it: There are attachments available to be included! In this case, please note that what would have been the body of the message is occupied by the warning string
- Case 2 is when there are no attachment, in which the case, the email text, if supplied, is the only information that is included in the local variable
$msg
; no MIME headers are needed in this case. (However, we could have specified just the MIME-Version header in this case – rewind back to the simplest MIME message presented earlier.) - The MIME message headers (MIME-Version, Content-Type, etc.) are created if there are attachments. To create the message body with the MIME Message headers, first the MIME message headers are created. Then the individual MIME parts available through the
$mimeheaders
array are processed in iteration. This is the point where the boundary marker ($boundary
) is actually used. In conformance with the rules, two hyphens are prefixed (>'--'.$boundary.CRLF
) for a MIME part and additionally, two hyphens are appended to the boundary marker ('--'.$boundary.'--'.CRLF;
) after the last MIME part to indicate the end-of-scope. - The completed message in the variable
$msg
is the return value of this method.
The next method,
gen_email()
completes (well, more or less) the MIME message created by the build_message()
method. Since build_message()
is an internal method, gen_email ()
creates the RFC 822 headers and appends the MIME information after a call to build_message()
.
<?php
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;
}
?>
The class member
$email
has the entire email message generated for an instance of our class. To avoid unnecessary recreation of the message, this method proceeds to create the email headers and to call build_message()
only if $email
is empty. However, you can force reprocessing by calling gen_email(true)
. (The caller will definitely want to do this if the “To” information is changed or a new attachment is added).gen_email()
creates the more familiar From header. Additionally it sets the subject to a generic (No Subject) if no subject was specified at all. We save the inclusion of the To and Subject headers until later. The method returns the completed email message and this concludes the task of creating the MIME message.