You are on page 1of 83

Inserting Images Into HTML Email

Images can be displayed within HTML email without physically inserting them.
This keeps email size down because the images do not travel with the email. Thus, there is less chance of getting
trapped in email filters when filtering rules consider the size of the email.
Images are downloaded only when the email is opened for reading or, sometimes, when the email is in the preview
pane.
The idea is simple. The way to make an HTML email like that is the way a web page is made.
The software that sends the email must, of course, be able to send HTML email. And there are a few other
considerations:
1. All image tag src attributes must have absolute http://... URLs as their values.
2. Some email reading software can not render HTML email, some only understand basic HTML tags, and
others interpret certain HTML tags differently than a browser would. Very few email reading software
renders HTML email as well as a browser would a similar web page.
Keep the HTML as simple as possible for the visual representation you are striving for.
In a moment, I will show you how to automatically insert the tags of newly uploaded images into outgoing email. But
first, let's see several methods of manually create an HTML email with an image visually embedded.
Let's use this image, caption, and paragraphs as our example:
Top of Form

Bottom of Form

The above uses only P, IMG, and BR tags. It's the most simple HTML one can use to insert an image with caption.
Next, let's see how one would center the image and caption on the page. Let's also reduce the size of the caption
text.
Top of Form

Bottom of Form
The above should work with most email readers that understand HTML. The DIV tag centers the image and the
caption (the centering stops where the cancel </DIV> tag is at), and the style attribute in the SPAN tag (with a
corresponding cancel </SPAN> tag) specifies a smaller font size.
Notice that an inline style was used to make the caption text smaller instead of a FONT tag. That's because FONT is
deprecated and, unlike browsers that started life recognizing FONT, email readers don't need to be backward
compatible.
Now, let's get more complicated and float the image and caption to the left side of the window and have the
paragraph after the picture printed to the right of the image. If the paragraph after the picture were large enough, it
would wrap under the picture after the space on the right is used up.
Top of Form

Bottom of Form

It is a bit much to expect all email readers to know how to float something to the left. But some will do it just fine.
Those that don't understand "float:left" will most likely begin the following paragraph below the picture, which may be
an acceptable degradation.
Now that you know several ways to display an image within an HTML email, I'll show you how to automatically insert
the tags of newly uploaded images.
The software to do the job is Master Form V4.
I'll use the most complicated method above as the base for the following examples. You'll be able to change the
template as desired.
The upload form will have 4 fields to be filled in:
1. Location of file to upload. (assuming field name="iupload")
2. The image width (optional, see note). (assuming field name="iwidth")
3. The image height (optional, see note). (assuming field name="iheight")
4. The caption to be printed with the image. (assuming field name="icaption")
Note: If the image width and/or height is not specified in the form, remove those two attributes from the email
template's IMG tag so no height or width is specified. (The email template is presented further below.) Specifying an
empty or non-number value for height or width might, with some email readers, translate into the number zero. A
height or width of zero would make the image invisible.
The form will also have 3 hidden fields:
1. Where to find the file with instructions where to store the uploaded image. (name="uploadedfilesaveinfo")
2. Where to find the email template. (name="emailtemplate")
3. Where the browser goes after the upload is complete. (name="redirect" or name="flowto")
The image must be stored in a publicly accessible directory. Publicly accessible means browsers can read files in it
without providing a password. Let's assume the file with instructions where to store the uploaded image is:
Top of Form
Bottom of Form

The above says the form field name="iupload" specifies the uploaded file name and to store the uploaded file in the
"/path/to/document/root/images" directory. That would be the complete directory path of the document root plus the
name of the subdirectory to store the images at, "images" in this case.
(The document root directory is the directory where browsers find your default home page. If you don't know the path
to your document root, Master Pre-Installation Testercan help, or you can ask your hosting company.)
When the image directory is a subdirectory of the document root named "images," the URL to the image directory will
be "http://example.com/images" (substitute domain name for your own).
Now, knowing the form field names, where the image will be stored, and the image subdirectory URL, we can
construct an email template. Here is an example:
Top of Form

Bottom of Form

If you won't be asking for the width and height of the image on the upload form, remove those attributes from the
email template.
As you can see, the file is uploaded, stored on the server, and an email with live information created from the
template. Open it in your email reader and, yep, you have an email with an image displayed within it — assuming you
have a capable email reader, of course.
It does exactly what you want it to do.
Will Bontrager
Please note: All information presented "as is". Click here for expert advice.

Will Bontrager asks:


Was it good information?
Click here to tell your friend.And Twitter. And ...
Question: Did you find this article interesting and understandable? How can it be improved? Your response is
anonymous. When done typing, click anywhere outside the box. [more info]
Please note: The article information is presented "as is". If you need expert advice on applying this information to
your web site, please Click Here.
Top of Form

Powered by "Real Time Reader Feedback" from WebSite's Secret.


Bottom of Form

A simple text email

Our first example will create a basic email message to "John Doe" and send it through
your Google Mail (GMail) account.

Email email = new SimpleEmail();


email.setHostName("smtp.gmail.com");
email.setSmtpPort(587);
email.setAuthenticator(new DefaultAuthenticator("username",
"password"));
email.setTLS(true);
email.setFrom("user@gmail.com");
email.setSubject("TestMail");
email.setMsg("This is a test mail ... :-)");
email.addTo("foo@bar.com");
email.send();
The call to setHostName("mail.myserver.com") sets the address of the outgoing SMTP
server that will be used to send the message. If this is not set, the system property
"mail.host" will be used.
Sending emails with attachments

To add attachments to an email, you will need to use the MultiPartEmail class. This class
works just like SimpleEmail except that it adds several overloaded attach() methods to
add attachments to the email. You can add an unlimited number of attachments either
inline or attached. The attachments will be MIME encoded.
The simpliest way to add the attachments is by using the EmailAttachment class to
reference your attachments.
In the following example, we will create an attachment for a picture. We will then attach
the picture to the email and send it.

import org.apache.commons.mail.*;
...

// Create the attachment


EmailAttachment attachment = new EmailAttachment();
attachment.setPath("mypictures/john.jpg");
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription("Picture of John");
attachment.setName("John");

// Create the email message


MultiPartEmail email = new MultiPartEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("The picture");
email.setMsg("Here is the picture you wanted");

// add the attachment


email.attach(attachment);

// send the email


email.send();
You can also use EmailAttachment to reference any valid URL for files that you do not
have locally. When the message is sent, the file will be downloaded and attached to the
message automatically.
The next example shows how we could have sent the apache logo to John instead.

import org.apache.commons.mail.*;
...
// Create the attachment
EmailAttachment attachment = new EmailAttachment();
attachment.setURL(new
URL("http://www.apache.org/images/asf_logo_wide.gif"));
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription("Apache logo");
attachment.setName("Apache logo");

// Create the email message


MultiPartEmail email = new MultiPartEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("The logo");
email.setMsg("Here is Apache's logo");

// add the attachment


email.attach(attachment);

// send the email


email.send();
Sending HTML formatted email

Sending HTML formatted email is accomplished by using the HtmlEmail class. This class
works exactly like the MultiPartEmail class with additional methods to set the html
content, alternative text content if the recipient does not support HTML email, and add
inline images.
In this example, we will send an email message with formatted HTML content with an
inline image.

import org.apache.commons.mail.HtmlEmail;
...

// Create the email message


HtmlEmail email = new HtmlEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("Test email with inline image");

// embed the image and get the content id


URL url = new
URL("http://www.apache.org/images/asf_logo_wide.gif");
String cid = email.embed(url, "Apache logo");

// set the html message


email.setHtmlMsg("<html>The apache logo - <img
src=\"cid:"+cid+"\"></html>");
// set the alternative message
email.setTextMsg("Your email client does not support HTML
messages");

// send the email


email.send();
First, notice that the call to embed() returns a String. This String is a randomly generated
identifier that must be used to reference the image in the image tag.
Next, there was no call to setMsg() in this example. The method is still available in
HtmlEmail but it should not be used if you will be using inline images. Instead, the
setHtmlMsg() and setTextMsg() methods were used.
Sending HTML formatted email with embedded images

The previous example showed how to create a HTML email with embedded images but
you need to know all images upfront which is inconvinent when using a HTML email
template. The ImageHtmlEmail helps you solving this problem by converting all external
images to inline images.

import org.apache.commons.mail.HtmlEmail;
...

// load your HTML email template


String htmlEmailTemplate = ....

// Create the email message


HtmlEmail email = new ImageHtmlEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("Test email with inline image");

// embed the image and get the content id


URL url = new
URL("http://www.apache.org/images/asf_logo_wide.gif");
String cid = email.embed(url, "Apache logo");

// set the html message


email.setHtmlMsg(htmlEmailTemplate, new
File("").toURI().toURL(), false);

// set the alternative message


email.setTextMsg("Your email client does not support HTML
messages");

// send the email


email.send();
First we create a HTML email template referencing some images. All referenced images
are automatically transformed to inline images starting from the current working
directory.
Debugging

The JavaMail API supports a debugging option that will can be very useful if you run into
problems. You can activate debugging on any of the mail classes by calling
setDebug(true). The debugging output will be written to System.out.
Authentication
If you need to authenticate to your SMTP server, you can call
the setAuthentication(userName,password) method before sending your email. This
will create an instance of DefaultAuthenticator which will be used by the JavaMail API
when the email is sent. Your server must support RFC2554 in order for this to work.
You can perform a more complex authentication method such as displaying a dialog box
to the user by creating a subclass of the javax.mail.Authenticator object. You will
need to override the getPasswordAuthentication() method where you will handle
collecting the user's information. To make use of your new Authenticator class, use
theEmail.setAuthenticator method.
Handling Bounced Messages
Normally, messages which cannot be delivered to a recipient are returned to the sender
(specified with the from property). However, in some cases, you'll want these to be sent
to a different address. To do this, simply call
thesetBounceAddress(emailAddressString) method before sending your email.
Technical notes: When SMTP servers cannot deliver mail, they do not pay any attention to
the contents of the message to determine where the error notification should be sent.
Rather, they refer to the SMTP "envelope sender" value. JavaMail sets this value
according to the value of the mail.smtp.from property on the JavaMail Session.
(Commons Email initializes the JavaMail Session using System.getProperties()) If this
property has not been set, then JavaMail uses the "from" address. If your email bean has
the bounceAddress property set, then Commons Email uses it to set the value
ofmail.smtp.from when the Session is initialized, overriding any other value which might
have been set.
Note: This is the only way to control the handling of bounced email. Specifically, the
"Errors-to:" SMTP header is deprecated and cannot be trusted to control how a bounced
message will be handled. Also note that it is considered bad practice to send email with an
untrusted "from" address unless you also set the bounce address. If your application
allows users to enter an address which is used as the "from" address on an email, you
should be sure to set the bounce address to a known good address.
Hi,

I am using PEAR mail system to send authenticated mails.I need to send HTML mails that has
alinks.It was working fine before i started using PEAR mail.Now i am not able to send HTML mails.

mail body looks like this:

$body = <<<EOD

Hiya $username

You might be interested in the current 'haves' and 'wants' on example.com

Latest Haves
<a
href="http://www.exmaple.com/product/have/64/Titan+Fast+Track+SunGlass">T
itan Fast Track SunGlass</a>
EOD;

If you follow this example there's no reason it shouldn't work:

<?
include('Mail.php');
include('Mail/mime.php');

// Constructing the email


$sender = "Leigh <leigh@no_spam.net>";
// Your name and email address
$recipient = "Leigh <leigh@no_spam.net>";
// The Recipients name and email address
$subject = "Test Email";
// Subject for the email
$text = 'This is a text message.';
// Text version of the email
$html = '<html><body><p>This is a html
message</p></body></html>'; // HTML version of the email
$crlf = "\n";
$headers = array(
'From' => $sender,
'Return-Path' => $sender,
'Subject' => $subject
);

// Creating the Mime message


$mime = new Mail_mime($crlf);

// Setting the body of the email


$mime->setTXTBody($text);
$mime->setHTMLBody($html);

$body = $mime->get();
$headers = $mime->headers($headers);

// Sending the email


$mail =& Mail::factory('mail');
$mail->send($recipient, $headers, $body);
?>

How To Code HTML Email Newsletters (All New Version)

Please note a version of this article is published at SitePoint which includes links to related articles
on their site. This article has been online since 2004.
Changes to this article are noted at the bottom of this article.
This article brings you up to date on how best to code HTML email so that it will display well in most
email software. It provides an exhaustive overview of how to code html email newsletters (even in
Outlook) with links to free html email templates, CSS compatability tables, services that test your
html email, and much more. This article strives to provide a comprehensive overview of all possible
resources online compared to other articles on this topic which may be vendor-specific or focus on
one aspect of how to code html email, for example, testing CSS styles across email software clients.
Here are some quick links if you only need specific information from this article:
• The Building Blocks
• Step 1: Use HTML Tables for Layout
• Step 2: Add in CSS Styles
• Step 3: Add HTML Email Best Practices
• Step 4: Code for GoogleMail, LotusNotes, and Outlook 2007
• FAQs: Create HTML Email in Outlook, Background Images, Create Anchor Links in Email, Add
Video to HTML Email
• “How to Code HTML Email” Slide Presentation
• Where to Learn More about Coding HTML Email, Including Free HTML Email Templates
• Changes to this article

The Building Blocks


Whether you use a template or hand code (my preference), there are two key building blocks for html
email:
• HTML tables control the design layout and some presentation
• Inline CSS controls presentation, for example, colors for backgrounds and fonts
The quickest and easiest way to see how HTML tables and inline CSS interact within an HTML email
is to download templates from Campaign Monitor and MailChimp, two email delivery services that
provide free templates (links are below in the Where to Learn More section).
When you open up their templates, you will notice several things we’ll discuss in more detail later:
• CSS style declarations appear below the BODY tag, not between the HEAD tags. If a template has
CSS declarations above the BODY tag, it’s simply a convenience: the email delivery service
(Campaign Monitor, in particular) moves these declarations down to inline styles as part of their
email delivery process.
• No CSS shorthand is used: instead of “font: 12px/16px Arial, Helvetica” break this shorthand into
its components of font-family, font-size, and line-height.
• SPANs and DIVs are used sparingly to achieve specific effects while HTML tables do the bulk of
the layout work.
• CSS style declarations are basic with no hacks required.

Step 1: Use HTML Tables for Layout


Determining the layout design is the first step in coding an html email. Single column and two-
column layouts work best for emails because they control the natural chaos that results when a lot of
content is pushed into such a small space as email.
• With a one column layout, typically there is a header that contains a logo and some (or all)
navigation links from the parent website. Below that are the intra-email links to stories further
down in the email. At the bottom of one column layouts are the footer (often with links that
repeat the top navigation) and detailed unsubscribe instructions.
• Two-column email layouts also use a header and footer. They also typically use a narrow side
column to contain features and links to more information. The wider column holds the main
content of the email.
• Promotional emails follow the same rules but with much less content and links. They often
include one to two messages and sometimes one big image with small explanatory text and links
below the image.
No matter how your email is designed, the most important content (or reference to that content)
should appear at or near the top of the email design, so it is visible immediately when a reader opens
your email. The top left of an email often is the first place people look when they open an email.
All of these email layout possibilities can be coded easily with html tables to divide up the space into
rows and columns. Using html tables also helps with problems caused by different email software
and how they can read the same email code differently.
The basic approach follows these steps in coding the email layout with html tables:
• For a two-column layout, create one table each for the header, the center two content columns,
and the footer. That’s three tables. Wrap these tables into another table that “wraps” or “frames”
the other tables. Use the same approach for one column layouts except the content table has one
column. This approach helps with email designs that break images into multiple table cells.
Otherwise, a single table with TD rows for header (with colspan=2 if the design is two column),
content, and footer should display fine for all but Lotus Notes email software.
• Use the HTML table attributes within the TABLE and TD tags, for example, to set the table
border=0, the valign=top, the align=left (or center, if that is the design), cellpadding=0,
cellspacing=0, and so on. This primarily helps older email readers to display the html email in a
minimally-acceptable way.
• Set the HTML table border=1 to help debug any problems with the internal alignment of TR and
TD tags in development. Then change it back to border=0 for testing and production.
While this approach might offend purists who prefer to code to the latest standards, you do not have
to be a complete primitive. No matter how badly LotusNotes displays html email, resorting to HTML
FONT tags is not required (although use of FONT tags cannot hurt, honestly). And while Outlook
2007′s HTML rendering engine is less than perfect, it does display basic HTML tables just fine.
Step 2: Add in CSS Styles
Once the email layout is coded as a set of nested HTML tables, the next step is to add in CSS styles.
Here are the steps to follow:
• First, put style information (style=) into the HTML tags, for example, TABLE, TD, P, A, and so
on.
• Place the CSS STYLE declaration right below the HTML BODY tag. Do not use the CSS STYLE
declaration in the HTML HEAD tags as is done when coding web pages. Google Mail, in
particular, looks for STYLE anywhere in the email and (helpfully) deletes it. And don’t bother to
use CSS LINK to a stylesheet. Google Mail, Hotmail, and other email software ignore, modify, or
delete these external references to a stylesheet.
• For the frame table, the one that contains the header, content, and footer tables, style the table
width at 98%. It turns out that Yahoo! mail needs the 1% cushion on either side to display the
email properly. If side gutters are critical to the email design, set the width at 95% or even 90% to
avoid potential problems. Of course, the tables inside the frame (wrapper) table are set for 100%.
• Put general font style information in the table TD closest to the content. This can mean repetitive
style declarations in multiple TD cells. Put font style definitions into heading (e.g. H1, H2), P, or A
tags only when necessary.
• Use DIVs sparingly to float small boxes of content and links to the right or left inside a table TD
cell. Google Mail appears to ignore the CSS Float property but Yahoo! and Hotmail work fine.
Outlook 2007 ignores floats. Sometimes it is better to code a more complex table layout than rely
on the Float property. Or, since email is easy to clutter, ask that the design put the floated content
in the narrow side column. Floats are the one part of an email design that might require the
design be reworked.
• While DIVs appear to be barely useful, SPANs appear to work almost every time because they
work inline. In some cases, SPANs can be used to position text above or below content, not just to
color or re-size type.
If you download and study the email templates from Campaign Monitor and Mail Chimp, you’ll see
they treat the frame table, the one that wraps the tables that hold content, as if it were the HTML
BODY tag. Campaign Monitor calls it “BodyImposter” which is a great way to think about the frame
or wrapper table. From a CSS perspective, the frame table does what the HTML BODY would do if
services like Google Mail didn’t disable or ignore the BODY tag.
Step 3: Best Practices
There are several best practices to follow to ensure your email code works well.
With the html email coded as described above, the next step is to test the email in a variety of email
software. Often this will identify problems that require workarounds.
The first test tools to use are the Firefox and Internet Explorer web browsers. If the email displays
well or perfectly in both browsers, chances are good that testing the email in Outlook, Yahoo!, Google
Mail, and other services will reveal only minor problems. You also might want to use the Internet
Explorer 6 web browser to test for Outlook 2003 which uses its rendering engine (see Resources
below if you need to download IE6).
Once the email appears fine in the two web browsers, use an email delivery service to send the email
to a range of test email accounts. Ideally this should include accounts with Yahoo!, Hotmail, and
Google Mail.
Which test accounts are used, however, should be determined by the domain names in the email
address list of people who will receive the email. For example, if there are few or no AOL subscribers
on this list, then it may be a waste of time and money to set up an AOL email account.
Here are the most common code tweaks that are found in this test phase:
• Sometimes a switch from percentage widths to fixed widths is needed. While this is not optimal,
because people can and do resize their email windows when reading, sometimes using a fixed
width is the only way for a layout to display properly in multiple email software.
• If there is a spacing issue with the columns in the email design, first tweak the cellpadding and
cellspacing attributes of the HTML tables. If that does not work, use CSS margin and padding
attributes. HTML spacing works better with older email software than spacing with CSS.
• Image displacement can occur when a TD cell is closed right below the IMG tag. This is an ancient
HTML problem. Putting the </td> right after (on the same line as) the IMG tag eliminates the
annoying and mystifying 1 pixel gap.
In addition, the following best practices are recommended:
• Avoid javascript. Most email software disables javascript.
• If an image is cut up and spread across several HTML table cells, test the email with many test
accounts. Sometimes it looks great in Outlook but shifts by 1 pixel or more in Hotmail and other
services. Also consider putting the image as a background image on a new html table (set the
background= value to the URL of your image) that encases all the table rows and columns that
would display parts of your background image; sometimes this achieves the same effect as cutting
an image up but with less code and better results. Note that Outlook 2007 does not display
background images. Be sure to test your email code with your target email software. (Campaign
Monitor has published a solution to the background problem with Outlook 2007 and 2010, Add a
Background Image to your Email in Two Simple Steps.)
• If you use background images, use the HTML table attribute background= instead of CSS. It
works more consistently across email software, for example, GMail.
• Store the email images on a web server, preferably in a folder separate from website images, for
example, in /images/email not /images. And don’t delete them. Some people open emails weeks
or months later, the same way people use bookmarks to return to websites.
• Be sure all your images use the alt, height, and width parameters. This helps with Google Mail as
well as when a reader has their images turned off. However, Outlook 2007 does not recognize the
alt= parameter.
• Use the target=”_blank” attribute for the HTML A tags so that people reading with a webmail
service don’t have the requested page appear within their webmail interface.
• While a 1×1 pixel image can be used to force spacing to create a precise email layout, spammers
use 1×1 pixel images to determine if their email has been opened.
• Avoid a big image above the fold in the email. This is another classic spammer practice and can
increase the likelihood an email will be tagged as spam.
My final test is to view the HTML email with images turned off. Outlook and some other email
software set images off by default, to prevent spammers from knowing your email address is active. I
set images off in my code by using my editor’s search and replace to delete some part of the src=
URLs in my file.
Make sure your email content displays fine without images. For example, if you use a background
image to provide a background color with white font color over it, make sure the default background
color for that part of the HTML table is dark, not white. Also be sure your alt=, height=, and width=
parameters are set for images so they can help readers understand your content without images.
Turning off your images will help you catch these issues and ensure the HTML email will display
effectively if people see your email with images off.
Once the html email is tweaked so that it displays well or perfectly in the test email accounts, the
next step is to go through a checklist. Verify that
• The From address displays properly (as a name, not a bare email address)
• The subject line is correct
• The contact information is correct and visually obvious
• The top of the email has the text, “You received this email because … Unsubscribe instructions are
at the bottom of this email.”
• There is text asking readers to add your From address to their email address book
• The top of your emails include a link to the web version of your email.
If it is important to know absolutely everything wrong with the html email code, try a service like
Browsercam.com or LitmusApp.com. These services show how your HTML and CSS code will display
as email or, in the case of Browsercam, as a web page.
Step 4: Coding for GoogleMail, LotusNotes, and Outlook 2007
Google Mail, LotusNotes, and Outlook 2007 present special coding problems. The good news? If you
code to account for their oddities, your html email code is more likely to display well in most if not all
email software.
Because Google cannot control how senders will code CSS and HTML, they have to take steps to
ensure their application displays properly regardless of the code quality of the html email that is
displayed.
As a result, Google Mail acts like an artifact of the mid 1990s when web standards were primitive. It
takes some work, but it is possible to crack open a Google Mail page and see just how convoluted
their approach is to rendering html email.
For one thing, Google Mail deletes any CSS style reference to a set of styles, no matter where it
appears in the email. And fonts displayed in html tables have the odd habit of appearing larger than
intended no matter how the html email is coded.
Here are coding techniques that appear to work well in Google Mail and older email software:
• Define the background color in a TD cell with bgcolor=, not the CSS style.
• Use the background= attribute in the TD cell for background images, not the CSS. A corollary is
that the background image can be made as tall as needed. If the content of an email template
might be short or tall depending on the email content, using an extra-tall background image this
way lets the email layout height shrink or expand based on the height of the copy from one email
to the next. Note, however, that Outlook 2007 ignores background images. (Campaign Monitor
has published a solution to the background problem with Outlook 2007 and 2010, Add a
Background Image to your Email in Two Simple Steps.)
• If it works better, use the padding style to control margins within a TD cell. The margin style does
not work in these cells. Padding does work.
• If a border around a TD cell is needed, Google Mail displays a border when defined in a DIV but
not when defined as a border style in a TD tag.
• If a light colored link against a dark background color is needed, put the font definition in the TD
cell (so it applies to P and A tags equally) then add a color= style to the A tag.
• If the P and A fonts appear to be different sizes, wrap the A tag in a P tag.
• Google Mail aggressively uses the right column of their interface which squeezes the html email
into the center panel. Be sure the padding style in the content TDs is set at 10 pixels all round so
text does not smash against the left and right edges.
• When testing an html email with a Google Mail account, it is likely one or more missing font
styles in the TD, H1, H2, P, A, and other tags will be found. Inspect every font carefully to make
sure Google Mail displays the fonts correctly.
Besides Google Mail, another hazard programmers face when coding email is less obvious:
LotusNotes. Many large corporations continue to support and upgrade their Notes installations. As
of 2004, IBM reported that 95 million people used Notes. Unfortunately, it is impossible to tell
which companies use Notes. So code html emails as described in this article. The more primitive the
code, the more likely it will work well, if not perfectly, with Notes.
That said, it is quite possible that Notes will introduce quirks that beggar belief, for example,
converting images to their proprietary format. Or Notes will simply ignore flawless basic html in one
email but display other html fine in another email.
Here is what apparently helps Lotus Notes display html email:
• Use a frame table that contains all the internal layout tables, for example, for the header, content,
and footer. This keeps the email together in one chunk of html. Pieces of the layout are less likely
to wander when displayed in Notes.
• Create a gutter around the frame (wrapper) table by setting the width to a percentage and/or
using the cellpadding to at least 5.
• Don’t use a style declaration in the head tags. It is the proper way to code to standards, but Notes
(like Google Mail) might delete your styles. Rely, instead, on inline styles within the TABLE, TD,
H1, H2, P, A, and other tags.
• Use absolute URLs to images stored on a web server. Notes cannot be prevented from converting
images, if it does, but using remote images might help.
• Intra page jumps, using named anchors, rarely work in Notes, if ever. It is best to avoid links that
jump down the email to a specific piece of content.
• Avoid colspans in the HTML table layouts. Notes apparently only handles basic table layouts,
especially older versions of the software.
• Be sure TD cell widths have accurate widths. Unlike web browsers, which automatically make all
cells the widest defined width, Notes sizes each TD cell based on its defined width.
• Centering an email layout usually does not work in Notes. Email layouts will have to be left-
aligned.
Using these techniques for Google Mail and Lotus Notes also will ensure your emails display fine in
Outlook 2007 with its older HTML rendering engine. Microsoft has published details about what
their email software will and won’t display properly (see Resources below for the link). And the
Email Standards Project has additional details. They also lobby companies like Microsoft to improve
their products.
The bottomline with Outlook 2007, LotusNotes, and Google Mail is that it requires coders to make
sure their HTML email code works across most email software. That means simple, standards-
compliant code works best in most if not all situations.
Many people who receive email prefer HTML over text for any number of reasons. For programmers,
however, the task of coding an HTML email appears both simple and horribly complex. Hopefully
this article has described many of the issues and coding strategies that work across email software so
that you can code HTML emails effectively.
What is the best idea to take from this article? If there is a choice to be made between a simple
coding solution and a more complex solution, simplicity always works better.
Frequently Asked Questions
How to Create HTML Email in Outlook
The basic approach is to create your html email as a separate html file and then create a signature file
and use your html email as the signature file. Then you open a new email message and add the new
signature file. This prevents Outlook from helpfully converting all your precious html code into text.
To create a signature file in Outlook:
1. Select Tools from the top menus, then Options, then the Mail Format tab in the Options pop-up
that will appear.
2. Down on the lower right of the Mail Format tab is a Signatures button. Click that button and a
Create Signature pop-up will appear.
3. Click the New button on the Create Signature pop-up and a Create New Signature pop-up
appears. Give your new signature a name and select Use this File as a Template and browse to
your HTML email.
Then create a new email message, click in the body of your email message, select Insert from the mail
dropdown menu and Signature then your new signature file.
People usually ask this question because they want to send html email from their internet account.
Don’t. Unless you know every person on your email list, too many bad things can happen if someone
tags your email as spam. If you send email through your business domain name, for example, all
your email will be tagged as spam. And you will be left to figure out how to get off any blacklists.
Even if you know everyone on your list, your internet provider may have a limit to how many
messages can be sent and may boot you off their service. It’s far less hassle to pay an email service
provider to deliver your email and worry about spam blacklists.
How to Use Background Images in GMail, Lotus Notes, and Other Services
Using images as a background in an html email is problematic. The old way is to carve up your image
and divide it among HTML table cells and rows, using the background= setting for the table. You
also can put the image in a new html table that encases all the table rows and columns that would
display parts of your background image; sometimes this achieves the same effect as cutting an image
up but with less code and better results. However, Outlook 2007, Google Mail, Lotus Notes 6, and
Live Mail do not display background images easily. Be sure to test your email code with your target
email software. Whatever you do, be sure your email design degrades nicely if and when the
background image does not display. If you use white text, for example, against a dark image, make
the default background color a dark color.
How to Create Anchor Links in an Email
Like image backgrounds, links within an email do not always work. You should test first. Over the
years, I have cracked open a few emails with intra-email links and find they use the basic HTML
anchor tag to link to a defined name= bookmark. The only oddity I’ve seen is the addition of
shape=rect in the anchor name code, as in, <a name=sometag shape=rect> But this was in an email
full of images.
How to Add Video to HTML Email
It is difficult but possible to add video to your html emails. Campaign Monitor has a great article,
“HTML5 and video in email“, that covers all the steps to make video available within email software
clients that can display video while degrading well for email software that cannot display video in an
html email. Their article includes test results across many email clients, as well as comments with
more insights and results.
“How to Code HTML Email” Slide Presentation
I recently presented this information in a slide presentation, if it is useful:
How to Code HTML Email Newsletters

View more presentations from Tim Slavin.

My presentation also included a one-sheet with resources for coding HTML email newsletters.
Where to Learn More
Besides this article, these online resources should be very helpful:
Email Standards Project
http://www.email-standards.org/
Probably the best start point for understanding exactly how different email software complies with
HTML and CSS. They also maintain an acid test they use to compare compliance across email
software. And you can participate to help improve standards.
Free HTML Email Templates
http://campaignmonitor.com/resources/templates.aspx
http://www.mailchimp.com/resources/html_email_templates/
Both email delivery services actively test their templates over time with different email software.
However, there are subtle differences to note. Campaign Monitor has its STYLE declaration within
the HEAD tag while Mail Chimp does not. Be sure to test your final HTML code with whatever
services are used by recipients in your email list.
Plain Text Email Design Guidelines
http://www.campaignmonitor.com/resources/plain-text-templates.aspx
This article has a number of simple ways to make text emails easier to scan.
Blocked Email Images
http://www.clickz.com/showPage.html?page=3413471
http://www.campaignmonitor.com/blog/archives/2005/11/email_design_guidelines_for_20.html
From 2004, the ClickZ article shows how major email software compares for blocked images and
preview panes. The Campaign Monitor article goes into greater detail with actual examples and ideas
how to combat default image off rendering of your emails, as well as designing your email to look
okay in preview panes.
Word 2007 HTML and CSS Rendering Capabilities in Outlook 2007
http://msdn.microsoft.com/en-us/library/aa338201.aspx
The official Microsoft description of what Outlook 2007 will and will not render for HTML and CSS.
Includes a link to a validator that works in Dreamweaver, as well as Microsoft editing tools.
A Guide to CSS Support in Email
http://www.campaignmonitor.com/blog/archives/2007/04/a_guide_to_css_support_in_emai_2.h
tml
Campaign Monitor, an email service provider, has taken Xavier Frenette’s excellent work
documenting CSS performance in a few email clients and expanded it to include Gmail, Hotmail,
Yahoo! and Windows Live Mail, as well as for the PC they cover Outlook 2003 and Outlook Express,
Lotus Notes, and Thunderbird and for the Mac they cover Mac Mail, Entourage, and Eudora.
MailChimp Email HTML Coding/Delivery Guide
http://www.mailchimp.com/resources/email_marketing_guide.phtml
Lots of great information about all aspects of html email, including how spam filters work.
CSS Support in HTML Emails of Hotmail, Yahoo! Mail, and Gmail by Xavier Frenette
http://www.xavierfrenette.com/articles/css-support-inwebmail/
This is excellent research and style by style results that show how these three webmail services
display CSS.
Secrets of HTML Email Series
http://www.graphics.com/modules.php?name=Sections&op=listarticles&secid=16
Some of this information is old but they have a good piece on Lotus Notes.
Lotus Notes Trial Software
http://www-128.ibm.com/developerworks/lotus/downloads/
Free downloads of their latest software if thoroughly testing an email with the Notes client software
is needed.
HTML Email and Web Page Testing Services
http://www.mailchimp.com MailChimp Inbox Inspector
http://www.campaignmonitor.com/testing/ Browsercam also has updated their service to display
your pages at a variety of screen resolutions.
https://browserlab.adobe.com/ Adobe BrowserLab currently is free and available anywhere with a
modern browser. It’s easy to use and displays the full range of bad browsers, specifically, IE6 and
IE7. But it also shows Chrome, Firefox, and Safari.
http://www.browsercam.com
http://www.litmusapp.com
Test compatiblity of your web pages with a variety of web browsers and operating systems. For email,
Browsercam simply shows you all the warts in your html code, even though your email might work
fine in Notes, Google Mail, and other difficult email software environments. Litmus shows how your
email appears in email software.
Best Practices For Bulletproof E-Mail Delivery
http://www.smashingmagazine.com/2007/10/16/best-practices-for-bulletproof-e-mail-delivery/
Excellent overview with some interesting ideas, resources, and details, for example, sending emails
on Tuesdays and Wednesdays from 2-3 p.m. That mirrors my experience for lists with business email
addresses (people come back from lunch and do email before meetings or getting back to work). The
best way to ensure delivery, however, is to use email inspection services provided by email delivery
vendors: it’s their job to keep up with what works best to deliver emails.
Testing Internet Explorer 6 Web Browser
Microsoft’s Expression Web SuperPreview lets you see how your email (or web pages) look in
software that uses the Microsoft web browser engine. Unfortunately, the Preview portion is not free.
You have to buy the whole package of Expression Web 3 software. Adobe’s Browserlab site is free and
might be a better option to check small changes and validate your html email displays fine.
Standalone Internet Explorer 6 Web Browser
http://tredosoft.com/Multiple_IE
This free software lets you run install and run IE6 and IE7 without causing conflicts. With Vista and
now Windows 7, this only works at installing IE6 because Windows only lets you have one IE
running at a time. Better to use BrowserLab to test against email clients that use the IE6 or IE7 html
rendering engine. Also, Microsoft’s Expression Web Super Preview is an easier and better option for
the future.
Changes to This Article
This article has been published and maintained since 2004. Here are the most recent changes:
• Updated references to background images to include a Campaign Monitor solution to the
background problem with Outlook 2007 and 2010 and GMail, Add a Background Image to your
Email in Two Simple Steps. (July 15, 2010)
• Embedded slides from a presentation I gave recently on How to Code HTML Email Newsletters.
It included a one-sheet with resources for coding HTML email newsletters. (June 15, 2010)
• Based on a comment, clarified the reason you might see CSS styles above the BODY tag open in
some email templates. The email delivery service that provides the templates moves these styles
down into inline styles as part of the delivery process. Added link to Best Practices For
Bulletproof E-Mail Delivery article in the Learn More section directly above. (May 26, 2010)
• Added link to Microsoft’s Expression Web SuperPreview software that shows how your html
email looks in older email software that uses the Microsoft web browser engine. (February 15,
2010)
• Added link to Adobe’s BrowserLab online service that, like BrowserCam, lets you see how your
web page (in this case, an html email) displays in older browser technology like IE6 and IE7. This
is useful for sending HTML email to older AOL email clients. Also added the FAQ about how to
add video to HTML email. (November 13, 2009)
• Added intra-page links to help people who arrive here from search engines. Also added link to
MailChimp’s HTML Email Inbox Inspector service. Added FAQs. (January 23, 2009)
• Updated link to MailChimp’s free HTML templates. Their URL changed without any automated
redirection. (February 23, 2009)
Share This Story:
|More

Related Stories
How to Add Background Images to Email Newsletters
How To Code HTML Email Newsletters: New Version Posted
How HTML Code Affects E-Mail Deliverability
Upgrade Your Organization’s Image with Slick HTML Newsletters
Windows XP SP2 Automatically Removes HTML Email Graphics
Outlook is Broken, Let’s Fix It
25 Questions Before You Send Email Offers and Newsletters
LikeDislike Communi Disqu
ty s

Add New Comment
Post as …

Showing 25 comments
Popular now

Sort by Subscribe by email Subscribe by RSS

Eddie 5 months ago

• Just wanted to say thanks for the great article. I'm coding some HTML emails for my site and my two big
gotchas that caught me: STYLE section in Gmail, and Floats in Outlook. Bleh.
• 1 person liked this. Like Reply

RCOComments 5 months ago in reply to Eddie

• Your welcome. And thanks for writing up what got you stuck. It helps when I rewrite the article.
• Like Reply

Mmeyer 3 weeks ago in reply to RCOComments

• Hi there,
I am having trouble with a newsletter format that has a table of contents. The table of contents works in web-based
email programs, but not Mac Mail.
Any help anyone can give, please do!
Melissa
mmeyer@eastsideinstitute.org
• Like Reply

123 3 days ago

• fucking rubish
• Like Reply

Troberts Roberts 2 weeks ago

• I am trying to find someone to write a script or a software that will embed a clients account number in each
story we publish. ie. The story link is http://www.eubankers.net/page.... - I need it to auto pick up the subscriber
email or account number from one source and drop it into each of the stories we send out to them. This ensures that
they don't have to login to read our news. Any thoughts would be most appreciated.
• Like Reply

Jarryd 4 weeks ago

• File > Insert Attachment > Insert As Text works just fine however :)
• Like Reply

RCOComments 4 weeks ago in reply to Jarryd

• Yeah, you caught me. This article documents Outlook 2003. Sorry. Thank you for pointing this out, and
for finding the solution (which helps everyone). I'll add this shortly and check this article against the latest Outlook
versions.
• Like Reply

Jarryd 4 weeks ago

• "3. Click the New button on the Create Signature pop-up and a Create New Signature pop-up appears. Give
your new signature a name and select Use this File as a Template and browse to your HTML email."

I don't get the option to 'Use this File as a Template'. I click 'New', then it gives me a dialog for the name, Okay and
Cancel are the only options I get. From here there is no sort of button that lets me insert an HTML file :(. I'm using
Outlook 2007
• Like Reply

Christian Vuong 2 months ago

• thanks for this helpful article... saved a lot of my time...


• Like Reply

Mohammed Haq 2 months ago

• Hi,
Great Article. This one answered many of my problems related to HTML emails. Thanks a Lot
• Like Reply

yvonne 2 months ago

• can't understand why each and every article in web tells about using padding in s... our lotus (8.5.1.) doesn't
support it - it's the same with cellspacing and partially cellpadding. Margin works, but not in s, only in divs.... And:
width in is ignored too so you have to use clear gifs in each and every empty cell.....
i'm getting nuts! and i'm a little disillusioned by Lotus 8.5.1. - have to rebuild all templates and anyway all articles in
web are not fitting to "our" internal lotus-behaviour....
• Like Reply

yvonne 2 months ago in reply to yvonne

• ouch - haha - editor eliminates my tags - so once again:


can't understand why each and every article in web tells about using padding in td... our lotus (8.5.1.) doesn't support
it - it's the same with cellspacing and partially cellpadding. Margin works, but not in tds, only in divs.... And: width in
is ignored too so you have to use clear gifs in each and every empty cell.....
i'm getting nuts! and i'm a little disillusioned by Lotus 8.5.1. - have to rebuild all templates and anyway all articles in
web are not fitting to "our" internal lotus-behaviour....
• Like Reply

Paul 3 months ago

• Great article! Very Useful!


One question, though: Is there a way to avoid an HTML e-mail to be reformatted when the message is forwarded?
I mean, forwarding is very important for a Newsletter (it is a success indicator). And I have found that MS Outlook
-for example- changes completely the HTML code when you try to forward it, because it uses the MS Word engine to
edit the message. Is there any way to avoid this change from happening?

Thanks!

Paul
• Like Reply

RCOComments 3 months ago in reply to Paul

• How email software handle the newsletter code when forwarding is not standardized. The only way to
begin to ensure your email looks the same or similar is to use an HTML table to wrap your email code and use HTML
tables to structure your email layout. That said, links often don't work with forwarded HTML emails, even I notice
when sent by Feedburner and other outfits you'd expect would have solved this problem reasonably well.
• Like Reply

Erin027 5 months ago

• so many great links!!! thanks!


i found a few site that might help designers:
www.email-gallery.com
http://www.campaignmonitor.com.../
• Like Reply

Ben 5 months ago

• Thank you for the 'How To Code HTML Email Newsletters (All New Version)' article. I am however having
problems emailing to Hotmail accounts where the recipient receives the HTML code and not a visual HTML email
which I get in MS Entourage for Mac. Please may you advice on what I should do to over come this? Is there anyway
of bypassing the spam firewall filter which is what I think is protecting Windows Live Hotmail accounts?
• Like Reply

Tim 5 months ago in reply to Ben

• To summarize a few emails back and forth. The problem turned out to be with Microsoft Entourage.
When Ben switched to Thunderbird to send HTML email, the problem went away. He also found that using an email
service provider was another way to get around Hotmail's spam filters.
• Like Reply

Reuven 6 months ago

• Hi,
I was having a great deal of trouble with the 1px bug, and your article really saved the day. Thanks so much for this
terrific post!
• Like Reply

Zu 16 hours ago in reply to Reuven

• The sentence "Putting the right after (on the same line as) the IMG tag eliminates the annoying and
mystifying 1 pixel gap" is missing a word???? .....Putting the right [SOMETHING MISSING???] after ....or do I just not
understand what this is saying!?
• Like Reply

RCOComments 13 hours ago in reply to Zu

• Sorry: somehow the </td> was cut from the text. I've put it back. Basically the close TD and the IMG tag
should appear on the same line to eliminate the 1 pixel gap. This gap is less prevalent today than years ago when
browsers were more primitive. But you might see it in older email software clients.
• Like Reply

Globalgroupbiz 6 months ago

• Great article. Bravo.


• Like Reply

zixmail 7 months ago

• hi, Learn how to code HTML emails from MailChimp, a professional email ... your HTML email along with a
plain-text alternative version of your message!
• Like Reply

Deepak 6 months ago in reply to zixmail

• plz send me newsletter code


• 1 person liked this. Like Reply

cf_gal 7 months ago

• "CSS style declarations appear below the BODY tag, not between the HEAD tags."

-- This no longer appears to be true for the Campaign Monitor templates. Has this requirement changed? The CM
templates claim to be tested in a variety of different email clients.
• Like Reply

Tim 7 months ago in reply to cf_gal

• Hi,

Campaign Monitor emailed me to say they put CSS declarations above the BODY tag in their templates as a
convenience, to make them easy to find and edit. When people send their templates through Campaign Monitor, their
service moves and converts the CSS code to inline declarations. As noted in the article above, inline CSS declarations
are the safest way to get CSS to survive email software. Thanks for asking a great question.

Tim
• Like Reply

Reactions

KarolinaJamula 2 weeks ago

From Twitter via BackType

• How To Code HTML Email Newsletters (All New Version) http://t.co/2vLT6wg via @RCOTweets

cre8it_nl 1 month ago

From Twitter via BackType

• How to code HTML newsletters: http://www.reachcustomersonline.com/2010/01/23/09.27.00/


clickcarts 2 months ago

From Twitter via BackType

• How To Code HTML Email Newsletters (All New Version) http://t.co/YbTQqRD via @RCOTweets

cierratag 2 months ago

From Twitter via BackType

• Como maquetar email newsletter, hay resources de todo aqui, esta dpm [ http://bit.ly/bSBTG1 ]

pablolarah 2 months ago

From Twitter via BackType

• How To Code HTML Email Newsletters (All New Version) | Reach Customers Online http://otf.me/4It

Brun_At 3 months ago

From Twitter via BackType

• How To Code HTML Email Newsletters (All New Version) | Reach Customers Online | Connect with Low-
Cost Tools and Kn... http://bit.ly/blr5pA

junysb3 3 months ago

From Twitter via BackType One more retweet from Brun_At

• How To Code HTML Email Newsletters (All New Version) | Reach Customers Online | Connect with Low-
Cost Tools and Kn... http://bit.ly/bE1BDQ

junysb3 3 months ago

From Twitter via BackType

• How To Code HTML Email Newsletters (All New Version) | Reach Customers Online | Connect with Low-
Cost Tools and Kn... http://bit.ly/blr5pA

junysb3 3 months ago

From Twitter via BackType

• How To Code HTML Email Newsletters (All New Version) | Reach Customers Online | Connect with Low-
Cost Tools and Kn... http://bit.ly/ccLHhA

mail
(PHP 4, PHP 5)
mail — Send mail
Report a bug

Description
bool mail ( string $to , string $subject , string $message [, string $additional_headers
[, string$additional_parameters ]] )

Sends an email.
Report a bug

Parameters

to

Receiver, or receivers of the mail.


The formatting of this string must comply with » RFC 2822. Some examples
are:

 user@example.com
 user@example.com, anotheruser@example.com
 User <user@example.com>
 User <user@example.com>, Another User
<anotheruser@example.com>

subject

Subject of the email to be sent.


Caution

Subject must satisfy » RFC 2047.

message

Message to be sent.
Each line should be separated with a LF (\n). Lines should not be larger than
70 characters.
Caution
(Windows only) When PHP is talking to a SMTP server directly, if a full stop is
found on the start of a line, it is removed. To counter-act this, replace these
occurrences with a double dot.
<?php
$text = str_replace("\n.", "\n..", $text);
?>

additional_headers (optional)

String to be inserted at the end of the email header.


This is typically used to add extra headers (From, Cc, and Bcc). Multiple extra
headers should be separated with a CRLF (\r\n).
Note:
When sending mail, the mail must contain a From header. This can be set
with theadditional_headers parameter, or a default can be set in php.ini.
Failing to do this will result in an error message similar to Warning: mail():
"sendmail_from" not set in php.ini or custom "From:" header missing.
The From header sets also Return-Path under Windows.
Note:
If messages are not received, try using a LF (\n) only. Some poor quality Unix
mail transfer agents replace LF by CRLF automatically (which leads to doubling
CR if CRLF is used). This should be a last resort, as it does not comply with »
RFC 2822.

additional_parameters (optional)

The additional_parameters parameter can be used to pass additional flags as


command line options to the program configured to be used when sending
mail, as defined by thesendmail_path configuration setting. For example, this
can be used to set the envelope sender address when using sendmail with
the -f sendmail option.
The user that the webserver runs as should be added as a trusted user to the
sendmail configuration to prevent a 'X-Warning' header from being added to
the message when the envelope sender (-f) is set using this method. For
sendmail users, this file is/etc/mail/trusted-users.

Report a bug
Return Values
Returns TRUE if the mail was successfully accepted for
delivery, FALSE otherwise.
It is important to note that just because the mail was accepted
for delivery, it does NOT mean the mail will actually reach the
intended destination.
Report a bug

Changelog
Version Description

All custom headers (like From, Cc, Bcc and Date)


are supported, and are not case-sensitive. (As
4.3.0
custom headers are not interpreted by the MTA in
(Window
the first place, but are parsed by PHP, PHP < 4.3
s only)
only supported the Cc header element and was
case-sensitive).

The additional_parameters parameter is disabled


4.2.3 in safe_mode and the mail() function will expose a
warning message and return FALSE when used.

4.0.5 The additional_parameters parameter was added.

Report a bug

Examples
Example #1 Sending mail.
Using mail() to send a simple email:
<?php
// The message
$message = "Line 1\nLine 2\nLine 3";

// In case any of our lines are larger than 70 characters


, we should use wordwrap()
$message = wordwrap($message, 70);

// Send
mail('caffeinated@example.com', 'My Subject', $message);
?>

Example #2 Sending mail with extra headers.


The addition of basic headers, telling the MUA the From and
Reply-To addresses:
<?php
$to = 'nobody@example.com';
$subject = 'the subject';
$message = 'hello';
$headers = 'From: webmaster@example.com' . "\r\n" .
'Reply-To: webmaster@example.com' . "\r\n" .
'X-Mailer: PHP/' . phpversion();

mail($to, $subject, $message, $headers);


?>

Example #3 Sending mail with an additional command


line parameter.
The additional_parameters parameter can be used to pass an
additional parameter to the program configured to use when
sending mail using the sendmail_path.
<?php
mail('nobody@example.com', 'the subject', 'the message',
null,
'-fwebmaster@example.com');
?>

Example #4 Sending HTML email


It is also possible to send HTML email with mail().
<?php
// multiple recipients
$to = 'aidan@example.com' . ', '; // note the comma
$to .= 'wez@example.com';

// subject
$subject = 'Birthday Reminders for August';

// message
$message = '
<html>
<head>
<title>Birthday Reminders for August</title>
</head>
<body>
<p>Here are the birthdays upcoming in August!</p>
<table>
<tr>
<th>Person</th><th>Day</th><th>Month</th><th>Year</
th>
</tr>
<tr>
<td>Joe</td><td>3rd</td><td>August</td><td>1970</td
>
</tr>
<tr>
<td>Sally</td><td>17th</td><td>August</td><td>1973<
/td>
</tr>
</table>
</body>
</html>
';

// To send HTML mail, the Content-type header must be set


$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1'
. "\r\n";

// Additional headers
$headers .= 'To: Mary <mary@example.com>, Kelly <kelly@ex
ample.com>' . "\r\n";
$headers .= 'From: Birthday Reminder <birthday@example.co
m>' . "\r\n";
$headers .= 'Cc: birthdayarchive@example.com' . "\r\n";
$headers .= 'Bcc: birthdaycheck@example.com' . "\r\n";

// Mail it
mail($to, $subject, $message, $headers);
?>

Note:
If intending to send HTML or otherwise Complex mails, it is
recommended to use the PEAR package» PEAR::Mail_Mime.
Report a bug

Notes
Note:
The Windows implementation of mail() differs in many ways
from the Unix implementation. First, it doesn't use a local binary
for composing messages but only operates on direct sockets
which means a MTA is needed listening on a network socket
(which can either on the localhost or a remote machine).
Second, the custom headers
like From:, Cc:, Bcc: and Date: are not interpreted by
the MTA in the first place, but are parsed by PHP.
As such, the to parameter should not be an address in the form
of "Something <someone@example.com>". The mail command
may not parse this properly while talking with the MTA.
Note:
It is worth noting that the mail() function is not suitable for
larger volumes of email in a loop. This function opens and closes
an SMTP socket for each email, which is not very efficient.
For the sending of large amounts of email, see the » PEAR::Mail,
and » PEAR::Mail_Queuepackages.
Note:
The following RFCs may be useful: » RFC 1896, » RFC 2045, »
RFC 2046, » RFC 2047, » RFC 2048,» RFC 2049, and » RFC
2822.
Report a bug

See Also
 imap_mail() - Send an email message
 » PEAR::Mail
 » PEAR::Mail_Mime

Mailparse ezmlm_hash

Last updated: Fri, 14 Jan 2011

add a noteUser Contributed Notes mail

Richard Neill 28-Dec-2010 11:54

If mail() encounters an error, it just returns false. To


find why, we need to discover where the sendmail command
put its error. On Linux, this is usually
/var/log/messages.

The mail errors don't end up in /var/log/httpd/errors


(because apache doesn't know that /usr/sbin/sendmail
returning false is an error), nor in /var/log/mail/
(because the email never got as far as postfix, and no
SMTP/delivery error occurred.)

shuitest at gmail dot com 03-Nov-2010 05:50


If you use mutt, do as below,

/usr/bin/mutt -s '$subject' -f /dev/null -e 'set copy=no'


-e 'set from = "{$GLOBALS[cfg][email_from]}"' -a
'$attach_file_full_path' '{$GLOBALS[cfg][email_to]}'
</dev/null 2>&1;

tschmieder at online dot de 23-Oct-2010 02:32

it seams to be better, to terminate additional headers


neither with "\n" nor with "\r\n", but to terminate them
with the php constant PHP_EOL.

The benefit is: this works fine as well on a LINUX based


Host as on a Windows based host.

As final result there must be produced a mail file


fulfilling the RFC2822 ff.

On a Linux system therfore in headers linebreaks like


"\n" are required due to the sendmail script transforming
them to "\r\n" (means CRLF).

On a Windows system the mail function speaks directly to


the SMTP Server (port 25) and therefore in headers
linebreaks like "\r\n" (means CRLF) are required at once.
Nobody else would care for transformation.

If you use the constant PHP_EOL instead of own character


sequences, the php installation will take care for the
required line ending as well on Linux as on Windows
installations.

Michiel Uitdehaag 30-Sep-2010 08:07

We had a LAMP setting with postfix as mail system. Our


additional headers were not interpreted correctly by a
receiving mailserver (Exchange/ENOD32) and a newline was
inserted after the first additional header.

It turns out that a internet/dos style newline (\r\n) in


the headers were converted to \r\r\n (ie: something
mindlessly replaced all \n with \r\n without seeing if \n
was already preceded by \r)

I don't know if this is something in PHP or postfix, but


seeing the comments below I suspect it is something of
PHP on *NIX in combination with non-sendmail mailers.
So, use your 'local' newline style for additional
headers, as opposed to the examples above.

I don't know if this is a bug anywhere. I don't know


which element exactly does the unix2dos translation. If
it is PHP, it should only replace ([^\r])\n with \1\r\n

Zane @ MLI 08-Sep-2010 10:17

Italian users cursing against "È" and other uppercase-


accented-vowels ("vocali maiuscole accentate"") in
subjects! While the lowercase ones ("è", "é" and so on)
work as expected, qmail doesn't handle the uppercase
ones.

To fix it, the only way I found was this:

<?php

function mail_utf8($to, $subject = '(No


subject)', $message = '', $header = '') {
$header_ = 'MIME-Version: 1.0' . "\r\n" . 'Content-
type: text/plain; charset=UTF-8' . "\r\n";
mail($to, '=?UTF-8?B?'.base64_encode($subject).'?=', $m
essage, $header_ . $header);
}

?>

It should apply to other languages too.

guy dot paddock at redbottledesign dot com 26-Aug-2010


09:19

If you are using SSMTP, pay attention to the "If messages


are not received, try using a LF (\n) only" note above
about "poor quality MTAs", since it appears that SSMTP
currently exhibits this behavior in version 2.62-r7.

This appears to be mentioned in this Debian bug report:


http://preview.tinyurl.com/2fqxswv

phadley at reliableid dot com 12-Aug-2010 01:20

The mail function will stop including headers if you


misspell one of them. It doesn't report an error, it
just puts the offending header and all that follow it in
the body of the message. My great transgression was
using MIME Version instead of MIME-Version, a lapse which
cost me several hours.

Porjo 07-Jul-2010 06:19

Make sure you enclose \r\n in double quotes (not single


quotes!) so that PHP can translate that into the correct
linefeed code

umangberi at gmail dot com 02-May-2010 08:41

Outlook 2007 seemed to be a little finicky with me to


have carriage returns in the headers. So any \r\n
resulted in messages that had default apache messages
sent over to me.

As soon as I removed \r from all of the headers, the


script started working fine. Hope that helped.

matthew dot mckay at uwrf dot edu 17-Feb-2010 09:57

Note: On some windows platforms this is NOT thread safe.


We are having email message bodies being sent out to the
wrong headers multiple times, some failing to send, and
other bizarre stuff. If you google search for "php mail
thread safe" you can find a ton of relevant information.
This is not a bug in php, there have been multiple bugs
closed with this issue being dismissed as not an issue
with PHP.

rch+php at online dot lt 02-Jan-2010 09:46

RFC-2822 is quite explicit, that "Though some message


systems locally store messages in this format (which
eliminates the need for translation between formats) and
others use formats that differ from the one specified in
this standard, local storage is outside of the scope of
this standard."

And it is not just "some", but most Unix mailers choke


when you try pipe CRLF instead of Unix line endings to
"sendmail" command. PHP is using line endings as is, so
you have better chances for success if you use Unix file
format or line endings.

Alex M. 23-Nov-2009 07:49

It is important to filter the form input to prevent


header injection. Here is a simple way:
<?php
# Anti-header-injection - Use before mail()
# By Victor Benincasa <vbenincasa(AT)gmail.com>

foreach($_REQUEST as $fields => $value)


if(eregi("TO:", $value) || eregi("CC:", $value) ||
eregi("CCO:", $value) || eregi("Content-Type", $value))
exit("ERROR: Code injection attempt denied! Please don't
use the following sequences in your message: 'TO:',
'CC:', 'CCO:' or 'Content-Type'.");
?>

--
Alex M.

Systemx 04-Nov-2009 10:29

Bare LFs in SMTP

Use This

<?php
// Fix any bare linefeeds in the message to make it
RFC821 Compliant.
$message = preg_replace("#(?<!\r)\n#si", "\r\n", $messag
e);

// Make sure there are no bare linefeeds in the headers


$headers = preg_replace('#(?<!\r)\n#si', "\r\n", $header
s);
?>

John 20-Oct-2009 06:38

A quick note about the optional flags that can be passed


to sendmail. -f will set the From address, -r will
override the default Return-path that sendmail generates
(typically the From address gets used). If you want your
bouncebacks to go to a different address than the from
address, try using both flags at once: "-f
myfromemail@example.com -r mybounceemail@example.com"

dtbaker.com.au 11-Oct-2009 03:59

An observation about safe_mode and mail()

It looks like multiple \r\n's are replaced by a single


\r\n inside the string passed to "additional_headers". I
can only re-produce this on a box running with safe_mode
enabled.

If (for some reason) your script crafts the entire email


message in the headers, this will most likely produce a
blank email on safe_mode boxes (like this script I've
been trying to get working).

Maven1 at example dot com 09-Oct-2009 08:28

I was having trouble with the newline and carriage return


characters when using the mail function in a custom
script within Joomla since the stupid input validations
kept stripping them (changed "/r/n" to "rn").

To get around this, I used chr(13) and chr(10) to insert


them.

<?php

$headers .= 'To: Mary <mary@example.com>, Kelly


<kelly@example.com>' . chr(13) . chr(10);
$headers .= 'From: Birthday Reminder
<birthday@example.com>' . chr(13) . chr(10);

?>

Hope that helps someone.

Clayton Ginsburg 18-Aug-2009 07:38

I recently had an issue where the mail() function would


work fine from the php cli but not from apache.

I eventually traced this down to the fact that I was


using apparmor

Specifically, I configured apparmor to deny the apache


user the ability to use /bin/dash

After changing apparmor to /bin/dash rix


and reloading the apparmor profile, mail worked

In other words, mail requires the account/program


executing the script to be able to use /bin/dash

I hope this helps someone

Anonymous 17-Aug-2009 06:29


UTF-8 and QMail

This function should work for all of you, who want to


switch to UTF-8 email - especially if using Qmail as
Mailserver.

QMail seems to have problems with the "\r\n" in the


header section. I found it helpful to replace them with
"\n".

<?php
function mail_utf8($to, $subject = '(No
subject)', $message = '', $from) {
$header = 'MIME-Version: 1.0' . "\n" . 'Content-type:
text/plain; charset=UTF-8'
. "\n" . 'From: Yourname <' . $from . ">\n";
mail($to, '=?UTF-8?B?'.base64_encode($subject).'?=', $m
essage, $header);
}
?>

Tomer 03-Aug-2009 06:31

I was trying to create a script that would send large


forms without having to get/post each value first and
came up with this... should help someone to save valuable
time.

<?php
$emailSentTo = "";
$subjectOfEmail = "";

//========= no need to edit bellow

// Set HTML Mail Header


$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-
1' . "\r\n";

// The Message
$message = $GLOBALS["HTTP_SERVER_VARS"]["REQUEST_URI"];

//Cleaning Message
$message = str_replace('?','<br><hr>',str_replace('/','Fi
le used for submittimg this form: ',str_replace('=',':
',str_replace('&','<br>',$message))));

// Sending
mail($emailSentTo, $subjectOfEmail, $message, $headers);
//Thanking
echo "<script language=\"javascript\"
type=\"text/javascript\">
alert('Thank You, We will contact you shortly.');
window.location = \"http://$_SERVER[HTTP_HOST]\";
</script>
";
?>

Edward 01-Aug-2009 09:08

Currently my hosting service is on Godaddy. When


attempting to use the mail function without the fifth
parameter containing "-f", my message headers would not
work.

Whenever your message headers do not work, simply try


using the fifth parameter:

<?php
mail($to, $subject, $message, $headers, "-
femail.address@example.com");
?>

php at caves dot org dot uk 28-Jul-2009 02:32

Setting an envelope-sender address avoids mail bounces


annoying your system administrator.

If your mail cannot be delivered, it will be rejected to


the address specified as the "SMTP-envelope-from" (or the
"envelope sender" or "return path", depending on the
terminology you like to use )

If you do not explicitly set an envelope-from address


then PHP will default to the php.ini setting which - if
you have not set this yourself - could be nobody@[your-
ISP-domain] or anonymous@[your-ISP-domain], for example.

To avoid bothering the person at that address - or


indeed, if you are wondering why you are not receiving
mail rejections yourself - you should use the "-f" option
in the <$additional_parameters> argument to set a valid
address.

(and, by the way: If you do this, but you do not set a


From: address in the <$additional_headers> argument then
PHP will set a default From: address of "From: Nobody
<your-envelope-sender-setting>". ).

php at caves dot org dot uk 28-Jul-2009 02:12

Problem: mail disappearing; not being sent

There are many reasons why your mail might fail to be


sent, but one particularly obscure reason is as follows.

You must take extra care if the machine that is sending


the mail also operates mail forwarding for your domain
and you are sending mail to a user at that domain. In
this situation, it is common for the MTA to avoid doing a
"proper" MX look-up because it "knows" that there is a
local list of mail-forwarding rules. This saves
resources, and normally shouldnt be a problem, of course.

HOWEVER, if you deliberately alter your MX record to


point to a mail server hosted elsewhere and, e.g. update
your mail forwarding rules at that location, AND the
server that sends your PHP-generated mail "decides" that
it will save resources by not checking the MX record THEN
it will use your old set of forwarding rules because it
is ignoring your MX record.

If an appropriate forwarding rule does not exist locally,


then the mail may be dropped without generating any error
(i.e. no "bounce" message).

The symptom of the problem is that mail to certain users


at your domain will be wrongly delivered or not delivered
at all.

An obscure problem, perhaps, but one that I have


experienced, and which took a long time to solve!

php at richardneill dot org 07-Jul-2009 04:29

Linux users have an easy way to send attachments using


the mutt program.
See: http://www.shelldorado.com/articles/mailattachments.
html

For example:
$cmd = "echo '$BODY_TEXT' | mutt -s '$SUBJECT' -a
'$filename_1' -a '$filename_2' '$email'";
exec ($cmd);
Anonymous 03-Jul-2009 04:22

I was (finally) able to get multipart HTML mail working.


The 'boundary' must be defined with double quotes, not
apostrophes.

$headers .= "Content-Type:
multipart/alternative;boundary=\"$boundary\";\n\n";

d dot r at usask dot ca 05-Jun-2009 04:44

The example indicates \r\n at the end of each line in the


headers but this was causing me problems as emails showed
some of the headers as part of the body. I simply used
only \n as in some of the other examples and the problem
went away.

marcel dot portela at gmail dot com 22-May-2009 05:32

To define a mail priority you have to put this lines in


the headers:

<?php
$headers = "MIME-Version: 1.0\n" ;
$headers .= "Content-Type: text/html;
charset=\"iso-8859-1\"\n";
$headers .= "X-Priority: 1 (Higuest)\n";
$headers .= "X-MSMail-Priority: High\n";
$headers .= "Importance: High\n";

$status = mail($to, $subject, $message,$headers);


?>

Here i've added many headers information including the


Priority...

aldertb at XS4ALL dot nl 23-Mar-2009 09:30

I experienced problems with removed euro signs and some


other accented letters. The text came from a DB but
contained the euro sign etcetera inside the mail
function, just as when you would define it as a string.
(Did die($newsletter['message']). It was lost in the mail
I received though! When I defined the message as a string
inside the sending function (overriding text from DB),
including euro sign as a single character, I DID receive
the email including euro sign!

This was experienced on 2 different email accounts. With


one I received no text after the euro sign.
But only when text came from mySQL DB from a longtext
Latin1-field...

I installed the pear mail class and this solved the


strange problem and could just send text from the DB...

andrei_a at btconnect dot com 18-Mar-2009 02:57

On some shared hosts like 1and1.co.uk, when using mail()


function with '-f' flag, email may be quietly 'dropped'
and not sent at all without any error message returned if
'-f' option is used without email address valid on this
host.
For example, if used as '-ftest@test.com' the email will
be dropped on 1and1 provider. But if you have a 'real'
mailbox on the server, for example 'black-
hole@mydomain.com', and you use '-fblack-
hole@mydomain.com' then the email will be sent. At the
same time envelope's 'Return-Path' will be set properly
to 'black-hole@mydomain.com' instead of
'test@shared.host.name'.

alex_ramos at sourceforge dot net 27-Feb-2009 03:37

Beware if you're trying to use "-f" or "-r" with the 5th


parameter of the PHP mail() function, and you're relying
on a plain vanilla install of sendmail on Linux, it won't
work. You'll have to either change the sendmail config
and add your script's userid to "trusted-users" (easier
said than done... good luck with that!), or, remove
sendmail and install postfix (much easier).

thelegs at gmail dot com 25-Feb-2009 03:06

As some SMTP servers (for example Argosoft Mail Server


for Windows) may lead into troubles when sending a mail
to "Full Name <user@domain.tld>" instead of simply
"user@domain.tld", the following may be a solution:

<?php
$Result = trim(preg_replace("/([\w\s]+)<([\S@._-]*)>/", "
$2", $Input));
?>

I'm not a PCRE guru, but this seems to work pretty good
with any number of e-mail addresses, even when the $Input
contains "mixed" address definitions (ie. some with Full
Name and some without).
Examples:

Input: "User 1 <user1@foo.tld>, User 2 <user2@foo.tld>,


user3@foo.tld"
Result: "user1@foo.tld, user2@foo.tld, user3@foo.tld";

Input: "user1@foo.tld, user2@foo.tld"


Result: "user1@foo.tld, user2@foo.tld"

The use of trim is optional, just to keep a nice space


after the comma separator. If you don't mind about
showing nice recipient lists to the MTA, I think this
would work as well:

<?php
$Result = preg_replace("/([\w\s]+)<([\S@._-]*)>/", "$2",
$Input);
?>

Anyway I hope that someone could improve these


expressions. :)

Erich at gasboysnospam dot net 19-Feb-2009 03:43

if your mail is failing (returns false) be aware that


many servers are configured to kill mail going out with a
bcc or cc header.

The ideal workaround is to use the smtp functions which


servers allow because of its better audit trail.
Alternatively call the mail function several times.

I've just spent about four hours trying to work out what
I was doing wrong!!

deepakkallungal at gmail dot com 23-Jan-2009 07:34

For solving japanese subject in php mail.

we had a problem was when we give shift-jis encoded test


for subject in mail, the mail received displayed as "BQ
Tech\ Ý t H [" in subject where the content in the mail
was showing correctly.
we solved it by using this code.

$subject =iconv( "Shift_JIS","EUC-JP", "BQ Tech 申込みフォー


ム");
we can convert like this for japanese encoding not
working correctly for japanese text.

orjtor 19-Jan-2009 08:17

This is my solution of problems with Windows Mail on


Vista. I got some of the headers in the mail body as
plain text. When I removed '\r' and left just '\n' at the
end of the two last lines of header it worked. This error
didn't show up in my yahoo mail.
<?php
$body = "<html>\n";
$body .= "<body style=\"font-family:Verdana, Verdana,
Geneva, sans-serif; font-size:12px; color:#666666;\">\n";
$body = $message;
$body .= "</body>\n";
$body .= "</html>\n";

$headers = "From: My site<noreply@my_site.com>\r\n";


$headers .= "Reply-To: info@my_site.com\r\n";
$headers .= "Return-Path: info@my_site.com\r\n";
$headers .= "X-Mailer: Drupal\n";
$headers .= 'MIME-Version: 1.0' . "\n";
$headers .= 'Content-type: text/html; charset=iso-
8859-1' . "\r\n";

return mail($recipient, $subject, $message, $headers);


?>

tyagi dot akhil at gmail dot com 04-Jan-2009 02:29

To send XML content in mail use this

Content-Type: text/xml

instead of Content-Type: text/html

Tim Johannessen 15-Dec-2008 02:59

I tried the example provided by [hn at nesland dot net]


but it didn't quite work, as the error:
Fatal error: Cannot redeclare mail()
was encountered.

Also, the runkit_function_rename() caused apache to exit


with Segmentation fault (11)

This works like a charm:


<?PHP
@dl("runkit.so");
@runkit_function_copy("mail", "__org_mail");
@runkit_function_remove("mail");
@runkit_function_copy("__new_mail", "mail");
@runkit_function_remove("__new_mail");

function __new_mail($to, $subject, $message, $additional_


headers = null, $additional_parameters= null) {
/* do your own mail function checks here */
return __org_mail($to, $subject, $message, $additional
_headers, $additional_parameters);
}
?>

Atleast it worked for me, stripping newlines from $to,


$subject, removing unwanted headers from
$additional_headers and adding new headers to
$additional_headers for debugging - this way I'll be able
to track the origin of the mail using the headers.

You'll need enable_dl = On in your php.ini and also


runkit.internal_override = "1"

I wanted to remove the execution of __org_mail(), so I


tried to add this to disable_functions in php.ini but
that didn't seem to work, so be aware that the original
function can still be executed, and found by using
get_defined_functions().

php at ontheroad dot net dot nz 04-Nov-2008 05:00

Another possible cause for the "501 5.5.4 Invalid


Address" type errors when sending mail from Windows is
specifying BCC or CC parameters with no value.

molotster on google mail com 13-Oct-2008 08:03

Note, that single line should not contain more than 78


character, but is not allowed to contain more than 998
characters.

The possible consequences are:


Over 78 - clients are allowed to display the message in a
"harder to read" way.
Over 998 - clients and servers are allowed to drop the
message or cause any buffer-limit error.
See:
http://www.faqs.org/rfcs/rfc2822 part 2.1.1.

duminda 17-Sep-2008 08:44

<?PHP
$title=$_POST['title'];
$name=$_POST['name'];
$email=$_POST['email'];
$telephone=$_POST['telephone'];
$fax=$_POST['fax'];
$address=$_POST['address'];
$country=$_POST['country'];
$comment=$_POST['comment'];

# -=-=-=- MIME BOUNDARY


$mime_boundary = "----MSA Shipping----".md5(time());
# -=-=-=- MAIL HEADERS
$to = "dlwijerathna@gmail.com";
//$to = "duminda@dumidesign.com";
//$to = "info@msashipping.com";
$subject = "Information Request from MSA Shipping -
Contact Form";
$headers = "From: MSA SHIPPING
<webmaster@msashipping.com>\n";
$headers .= "Reply-To: MSA Shipping
<webmaster@msashipping.com>\n";
$headers .= "BCC: dumidesign@gmail.com";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/alternative;
boundary=\"$mime_boundary\"\n";

$message .= "--$mime_boundary\n";
$message .= "Content-Type: text/html; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 8bit\n\n";

$message .= "<html>\n";
$message .= "<body style=\"font-family:Verdana, Verdana,
Geneva, sans-serif; font-size:12px; color:#666666;\">\n";

$message .= "<table width=\"800\" height=\"159\"


border=\"0\" cellpadding=\"0\" cellspacing=\"0\" >";
$message .="<tr>";
$message .="<td height=\"66\" colspan=\"4\"
bgcolor=\"#CCCCCC\"></td>";
$message .="</tr>";
$message .="<tr>";
$message .="<td width=\"1%\"></td>";
$message .="<td colspan=\"3\">&nbsp;</td>";
$message .="</tr>";
$message .="<tr>";
$message .="<td>&nbsp;</td>";
$message .="<td width=\"100\"><b>Title</b></td>";
$message .="<td align=\"left\" >:</td>";
$message .="<td>$title</td>";
$message .="<tr>";
$message .="<td>&nbsp;</td>";
$message .="<td><b>Name</b></td>";
$message .="<td>:</td>";
$message .="<td>$name</td>";
$message .="</tr>";
$message .="</tr>";
$message .="<tr>";
$message .="<td>&nbsp;</td>";
$message .="<td><b>E-mail</b></td>";
$message .="<td>:</td>";
$message .="<td>$email</td>";
$message .="</tr>";
$message .="<tr>";
$message .="<td>&nbsp;</td>";
$message .="<td><b>Telephone</b></td>";
$message .="<td>:</td>";
$message .="<td>$telephone</td>";
$message .="</tr>";
$message .="<tr>";
$message .="<td>&nbsp;</td>";
$message .="<td><b>Fax</b></td>";
$message .="<td>:</td>";
$message .="<td>$fax</td>";
$message .="</tr>";
$message .="<tr>";
$message .="<td>&nbsp;</td>";
$message .="<td><b>Country</b></td>";
$message .="<td>:</td>";
$message .="<td>$country</td>";
$message .="</tr>";
$message .="<tr>";
$message .="<td>&nbsp;</td>";
$message .="<td><b>Comments</b></td>";
$message .="<td>:</td>";
$message .="<td>$comment</td>";
$message .="</tr>";
$message .="<tr>";
$message .="<td height=\"21\" colspan=\"4\"
bgcolor=\"#CCCCCC\"></td>";
$message .="</tr>";
$message .="</table>";
$message .= "</body>\n";
$message .= "</html>\n";
# -=-=-=- FINAL BOUNDARY
$message .= "--$mime_boundary--\n\n";
# -=-=-=- SEND MAIL
$mail_sent = @mail( $to, $subject, $message, $headers );
//echo $mail_sent ? "Mail sent" : "Mail failed";
if($mail_sent)
{
header('Location:contactus.php?msg=yes');
}
else
{
header('Location:contactus.php?msg=no');
}
?>

webmaster at plumage dot nl 01-Sep-2008 09:53

The work-around for a large quantity of recipients is


putting the adresses in the header-section as Bcc
adresses.
In this way the mail()-function opens and closes the SMTP
connection only once:

<?php
$count_recip= count($recip);//where $recip represents an
array of mail-adresses, from MySql-query or otherwise
$count='0';
$headers.="Bcc: ";
while($count < $count_recip){
$headers.=$recip[$count].", ";
$count ++;
}
$headers.="admin@mailinglist.com\r\n";
?>

bob 15-Jul-2008 08:51

If the Cc or Bcc lines appear in the message body, make


sure you're separating header lines with a new line (\n)
rather than a carriage return-new line (\r\n). That
should come at the very end of the headers.

akam 28-May-2008 01:55

There differenece in body, headers of email (with


attachment, without attachment), see this complete
example below:
work great for me (LINUX , WIN) and (Yahoo Mail, Hotmail,
Gmail, ...)
<?php
$to = $_POST['to'];
$email = $_POST['email'];
$name = $_POST['name'];
$subject = $_POST['subject'];
$comment = $_POST['message'];

$To = strip_tags($to);
$TextMessage =strip_tags(nl2br($comment),"<br>");
$HTMLMessage =nl2br($comment);
$FromName =strip_tags($name);
$FromEmail =strip_tags($email);
$Subject =strip_tags($subject);

$boundary1 =rand(0,9)."-"
.rand(10000000000,9999999999)."-"
.rand(10000000000,9999999999)."=:"
.rand(10000,99999);
$boundary2 =rand(0,9)."-".rand(10000000000,9999999999).
"-"
.rand(10000000000,9999999999)."=:"
.rand(10000,99999);

for($i=0; $i < count($_FILES['youfile']['name']); $i++){


if(is_uploaded_file($_FILES['fileatt']['tmp_name'][$i])
&&
!empty($_FILES['fileatt']['size'][$i]) &&
!empty($_FILES['fileatt']['name'][$i])){

$attach ='yes';
$end ='';

$handle =fopen($_FILES['fileatt']['tmp_name']
[$i], 'rb');
$f_contents =fread($handle, $_FILES['fileatt']
['size'][$i]);
$attachment[]=chunk_split(base64_encode($f_contents));
fclose($handle);

$ftype[] =$_FILES['fileatt']['type'][$i];
$fname[] =$_FILES['fileatt']['name'][$i];
}
}

/********************************************************
*******
Creating Email: Headers, BODY
1- HTML Email WIthout Attachment!! <<-------- H T M L
---------
********************************************************
*******/
#---->Headers Part
$Headers =<<<AKAM
From: $FromName <$FromEmail>
Reply-To: $FromEmail
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="$boundary1"
AKAM;

#---->BODY Part
$Body =<<<AKAM
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="$boundary1"

This is a multi-part message in MIME format.

--$boundary1
Content-Type: text/plain;
charset="windows-1256"
Content-Transfer-Encoding: quoted-printable

$TextMessage
--$boundary1
Content-Type: text/html;
charset="windows-1256"
Content-Transfer-Encoding: quoted-printable

$HTMLMessage

--$boundary1--
AKAM;

/********************************************************
*******
2- HTML Email WIth Multiple Attachment <<-----
Attachment ------
********************************************************
*******/

if($attach=='yes') {
$attachments='';
$Headers =<<<AKAM
From: $FromName <$FromEmail>
Reply-To: $FromEmail
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="$boundary1"
AKAM;

for($j=0;$j<count($ftype); $j++){
$attachments.=<<<ATTA
--$boundary1
Content-Type: $ftype[$j];
name="$fname[$i]"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="$fname[$j]"

$attachment[$j]

ATTA;
}

$Body =<<<AKAM
This is a multi-part message in MIME format.

--$boundary1
Content-Type: multipart/alternative;
boundary="$boundary2"

--$boundary2
Content-Type: text/plain;
charset="windows-1256"
Content-Transfer-Encoding: quoted-printable

$TextMessage
--$boundary2
Content-Type: text/html;
charset="windows-1256"
Content-Transfer-Encoding: quoted-printable

$HTMLMessage

--$boundary2--

$attachments
--$boundary1--
AKAM;
}

/********************************************************
*******
Sending Email
********************************************************
*******/
$ok=mail($To, $Subject, $Body, $Headers);
echo $ok?"<h1> Mail Sent</h1>":"<h1> Mail not SEND</h1>";
?>

richard at richard-sumilang dot com 22-Mar-2008 08:12

If you are using the sendmail app from an exim package or


something you don't really need to change the normal
parameters PHP gives it (-t -i) as other posts
described.

I just added "-f myemail@foo.com" and it worked.

One thing that got me stuck for a few hours was trying to
figure out why the return-path was set as the user (user
running php) and not what I was setting it with the -f
option then I later found at that in order to forcefully
set the return-path the user account running the command
must be in exim's trusted users configuration! It helps
to add trusted_groups as well then everything works
fine :)
- Richard Sumilang

jano ATSOMERANDOMTEXTjanogarcia es 28-Jan-2008 10:31

This is a simple and quick (dirty?) fix for encoding long


UTF-8 email subjects.

<?php

$subject= mb_encode_mimeheader($subject,"UTF-
8", "B", "\n");

?>

Changing the $transfer_encoding parameter* from B


(Base64) to Q (Quoted-Printable) seems to work too.

*See the mb_encode_mimeheader documentation


here http://php.net/manual/en/function.mb-encode-
mimeheader.php
This one is based on the previously posted solution by
J.Halmuhttp://php.net/manual/en/function.mail.php#75886 ,
added the two last parameters to prevent long subjects
from breaking the email. It worked flawlessly on a RHEL
environmet. No further tests, sorry.

Tomix 17-Jan-2008 03:53

send e-mail in utf-8

there is already a solution from omgs. but with a longer


subject line there could be problem (splitting the
subject line in a encoded character).

here my solution:

<?php
// hmm no better solution?
function imap8bit(&$item, $key) {
$item = imap_8bit($item);
}

function email($e_mail, $subject, $message, $headers)


{
// add headers for utf-8 message
$headers .= "\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/plain; charset=utf-
8\r\n";
$headers .= "Content-Transfer-Encoding: quoted-
printable\r\n";

// encode subject
//=?UTF-8?Q?encoded_text?=

// work a round: for subject with wordwrap


// not fixed, no possibility to have one in a single
char
$subject = wordwrap($subject, 25, "\n", FALSE);
$subject = explode("\n", $subject);
array_walk($subject, imap8bit);
$subject = implode("\r\n ", $subject);
$subject = "=?UTF-8?Q?".$subject."?=";

// encode e-mail message


$message = imap_8bit($message);

return(mail("$e_mail", "$subject", "$message", "$headers"


));
}
?>

mortoray at ecircle-ag dot com 10-Jan-2008 03:35

Apparently if using the mbstring library, and using


overriden functions, the "mail" command appears to use
"Content-Transfer-Encoding: BASE64" by default. Which if
you combine it with PEAR Mail_Mime you'll get mails that,
although they appear RFC compliant, not mailer can read
correctly.

To fix this it appears you should add a fixed header in


the mail command (this one assumes the pear mime module
is 7bit clean, perhaps 8bit would also be fine)

<?php $headers['Content-Transfer-Encoding'] = '7bit'; ?>

d 25-Dec-2007 09:39

When sending html formatted mails to gmail accounts you


might notice that the html is shown in plain text. This
happens when you send from an unix system and gmail
treats the "\r\n" line ends in a wrong way. Use "\n"
instead at it will be fine.

Content-Type: text/html; charset=iso-8859-1\n


instead of
Content-Type: text/html; charset=iso-8859-1\r\n

hn at nesland dot net 03-Nov-2007 12:37

Tired of idiots and imbeciles who creates unsecure php-


code and lets spammers abuse mail()? Try this dirty
trick:

With auto_prepend, prepend this file:


<?php
// You need to install pecl-module, runkit.
dl("runkit.so");

// We could rename the function, but that currently makes


my apache segfault, but this works :-P
runkit_function_copy ( "mail","intmail" );
runkit_function_remove( "mail" );

function mail( $to, $subject, $message, $additional_heade


rs = null, $additional_parameters =null ) {
$___domain = $_SERVER['SERVER_NAME'];

$fp = fopen("/tmp/my_super_mail_logg", "a");


fwrite( $fp, date("d.m.y H:i:s") . "
" . $___domain . ": $to / $subject\n");
fclose( $fp );

return intmail( $to, $subject, $message, $additional_head


ers, $additional_parameters );
}
?>

You probably shouldn't log to /tmp, or any other place as


the webserver-user, see syslog-functions ;)

And of course you can manipulate the different


parameters, like adding custom headers to each email (For
instance; "X-From-Web: {$_SERVER['SERVER_NAME']}")..

phpcoder at cyberpimp dot ig3 dot net 27-Sep-2007 03:51

In addition to the $to parameter restrictions on Windows


(ie. address can not be in "name <user@example.com>"
format), the same restrictions apply to the parsed Cc and
Bcc headers of the $additional_headers parameter.

However, you can include a To header in


$additional_parameters which lists the addresses in any
RFC-2822 format. (For display purposes only. You still
need to list the bare addresses in the $to parameter.)

Gianluigi_Zanettini-MegaLab.it 10-Aug-2007 06:57

Please note that using an address in this format "Zane,


CEO - MegaLab.it" <myaddrr@mydomain> (" are needed due to
comma) works as expected under *nix, but WON'T WORK under
Windows.

This is an example

<?php
mail("\"Zane, CEO - MegaLab.it\"
<myaddrr@mydomain>", "prova da test_zane", "dai
funziona...");
?>

It works under *unix, but it doensn't under Win:


different error are reported:

Warning: mail() [function.mail]: SMTP server response:


553 5.0.0 <"Zane>... Unbalanced '"'

Warning: mail() [function.mail]: SMTP server response:


501 5.5.4 Invalid Address

J.Halmu 20-Jun-2007 11:10

I use text/plain charaset=iso-8859-1 and get bad headers


complain from amavis. This helped me:

[code]
$subject = mb_encode_mimeheader('ääööö test test
öäöäöä','UTF-8');
[/code]

php-version 5.2.2

Alex Jaspersen 31-May-2007 06:03

For qmail users, I have written a function that talks


directly to qmail-queue, rather than going through the
sendmail wrapper used by mail(). Thus it allows more
direct control over the message (for example, you can
adapt the function to display "undisclosed recipients" in
to the To: header). It also performs careful validation
of the e-mail addresses passed to it, making it more
difficult for spammers to exploit your scripts.

Please note that this function differs from the mail()


function in that the from address must be passed as a
_separate_ argument. It is automatically put into the
message headers and _does not_ need to be included in
$additional_headers.

$to can either be an array or a single address contained


in a string.
$message should not contain any carriage return
characters - only linefeeds.

No validation is performed on $additional_headers. This


is mostly unnecessary because qmail will ignore any
additional To: headers injected by a malicious user.
However if you have some strange mail setup it might be a
problem.

The function returns false if the message fails


validation or is rejected by qmail-queue, and returns
true on success.

<?php
function qmail_queue($to, $from, $subject, $message, $add
itional_headers = "")
{
// qmail-queue location and hostname used for
Message-Id
$cmd = "/var/qmail/bin/qmail-queue";
$hostname = trim(file_get_contents("/var/qmail/contro
l/me"));

// convert $to into an array


if(is_scalar($to))
$to = array($to);

// BEGIN VALIDATION
// e-mail address validation
$e = "/^[-+\\.0-9=a-z_]+@([-0-9a-z]+\\.)+([0-9a-z])
{2,4}$/i";
// from address
if(!preg_match($e, $from)) return false;
// to address(es)
foreach($to as $rcpt)
{
if(!preg_match($e, $rcpt)) return false;
}

// subject validation (only printable 7-bit ascii


characters allowed)
// needs to be adapted to allow for foreign languages
with 8-bit characters
if(!preg_match("/^[\\040-\\176]+$/", $subject))
return false;

// END VALIDATION

// open qmail-queue process


$dspec = array
(
array("pipe", "r"), // message descriptor
array("pipe", "r") // envelope descriptor
);
$pipes = array();
$proc = proc_open($cmd, $dspec, $pipes);
if(!is_resource($proc)) return false;
// write additional headers
if(!empty($additional_headers))
{
fwrite($pipes[0], $additional_headers . "\n");
}

// write to/from/subject/date/message-ID headers


fwrite($pipes[0], "To: " . $to[0]); // first
recipient
for($i = 1; $i < sizeof($to); $i++) // additional
recipients
{
fwrite($pipes[0], ", " . $to[$i]);
}
fwrite($pipes[0], "\nSubject: " . $subject . "\n");
fwrite($pipes[0], "From: " . $from . "\n");
fwrite($pipes[0], "Message-Id:
<" . md5(uniqid(microtime())) . "@" . $hostname . ">\n");
fwrite($pipes[0], "Date: " . date("r") . "\n\n");
fwrite($pipes[0], $message);
fwrite($pipes[0], "\n");
fclose($pipes[0]);

// write from address and recipients


fwrite($pipes[1], "F" . $from . "\0");
foreach($to as $rcpt)
{
fwrite($pipes[1], "T" . $rcpt . "\0");
}
fwrite($pipes[1], "\0");
fclose($pipes[1]);

// return true on success.


return proc_close($proc) == 0;
}
?>

Geoff in Montreal 01-May-2007 10:07

Here is a PHP Mail Multipart/Alternative (Plain Text and


HTML) code for *nix servers (Unix Like Servers)... if you
are hosted on a windows server, simply replace all "\n"
or "\n\n" in the below code to "\r\n" or "\r\n\r\n"
respectively.

This code is for anyone who has already written an HTML


page for their PHP mail... there are several PHP > HTML
free translators on the internet. You may use one of
them to translate your HTML code to PHP to insert into
the following code. All there needs to change is to
place a backslash before any quotations (EX: ... confirm
that \"Our Company\" has ...), and to end each line with
a newline character (EX: \n )...

This code method has been successfully tested with Apple


Mail, Microsoft Outlook, G-Mail, and Yahoo Mail. I hope
this helps out anyone that is writing a
multipart/alternative PHP mailer script.

<?php

# -=-=-=- PHP FORM VARIABLES (add as many as you would


like)

$name = $_POST["name"];
$email = $_POST["email"];
$invoicetotal = $_POST["invoicetotal"];

# -=-=-=- MIME BOUNDARY

$mime_boundary = "----Your_Company_Name----".md5(time());

# -=-=-=- MAIL HEADERS

$to = "$email";
$subject = "This text will display in the email's Subject
Field";

$headers = "From: Our Company


<company@ourcompany.com>\n";
$headers .= "Reply-To: Our Company
<company@ourcompany.com>\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/alternative;
boundary=\"$mime_boundary\"\n";

# -=-=-=- TEXT EMAIL PART

$message = "--$mime_boundary\n";
$message .= "Content-Type: text/plain; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 8bit\n\n";

$message .= "$name:\n\n";
$message .= "This email is to confirm that \"Our
Company\" has received your order.\n";
$message .= "Please send payment of $invoicetotal to our
company address.\n\n";
$message .= "Thank You.\n\n";

# -=-=-=- HTML EMAIL PART

$message .= "--$mime_boundary\n";
$message .= "Content-Type: text/html; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 8bit\n\n";

$message .= "<html>\n";
$message .= "<body style=\"font-family:Verdana, Verdana,
Geneva, sans-serif; font-size:14px;
color:#666666;\">\n";
$message .= "$name:<br>\n";
$message .= "<br>\n";
$message .= "This email is to confirm that \"Our
Company\" has received your order.<br>\n";
$message .= "Please send payment of $invoicetotal to our
company address.<br>\n\n";
$message .= "<br>\n";
$message .= "Thank You.<br>\n\n";
$message .= "</body>\n";
$message .= "</html>\n";

# -=-=-=- FINAL BOUNDARY

$message .= "--$mime_boundary--\n\n";

# -=-=-=- SEND MAIL

$mail_sent = @mail( $to, $subject, $message, $headers );


echo $mail_sent ? "Mail sent" : "Mail failed";

?>

Josh 09-Mar-2007 06:05

While trying to send attachments I ran into the problem


of having the beginning part of my encoded data being cut
off.

A fact that I didn't see mentioned anywhere explicitly


(except maybe in the RFC, which admittedly I didn't read
fully) was that two newlines are required before you
start the encoded data:

Content-Transfer-Encoding: base64\n
Content-Type: application/zip; name="test_file.zip"\n
\n //<--- if this newline isn't here your data will get
cut off
DATA GOES HERE

hans111 at yahoo dot com 01-Mar-2007 04:54

I had a lot of trouble trying to send multipart messages


to gmail accounts until I discovered gmail does not like
carriage returns, even under unix I have to use only new
lines (\n) and forget about the (\r) . Other email
clients such as eudora, outlook, hotmail or yahoo seem
not to have issues about the "missing" \r . Hope it
helps.

bigtree at dontspam dot 29a dot nl 28-Feb-2007 12:46

Since lines in $additional_headers must be separated


by \n on Unix and \r\n on Windows, it might be useful to
use the PHP_EOL constant which contains the correct value
on either platform.

Note that this variable was introduced in PHP 5.0.2 so to


write portable code that also works in PHP versions
before that, use the following code to make sure it
exists:

<?php
if (!
defined('PHP_EOL')) define ('PHP_EOL', strtoupper(substr(
PHP_OS,0,3) == 'WIN') ? "\r\n" :"\n");
?>

admin at chatfamy dot com 30-Jan-2007 08:37

One thing it can be difficult to control with this


function is the envelope "from" address. The envelope
"from" address is distinct from the address that appears
in the "From:" header of the email. It is what sendmail
uses in its "MAIL FROM/RCPT TO" exchange with the
receiving mail server. It also typically shows up in the
"Return-Path:" header, but this need not be the case. The
whole reason it is called an "envelope" address is that
appears _outside_ of the message header and body, in the
raw SMTP exchange between mail servers.

The default envelope "from" address on unix depends on


what sendmail implementation you are using. But typically
it will be set to the username of the running process
followed by "@" and the hostname of the machine. In a
typical configuration this will look something like
apache@box17.isp.net.

If your emails are being rejected by receiving mail


servers, or if you need to change what address bounce
emails are sent to, you can change the envelope "from"
address to solve your problems.

To change the envelope "from" address on unix, you


specify an "-r" option to your sendmail binary. You can
do this globally in php.ini by adding the "-r" option to
the "sendmail_path" command line. You can also do it
programmatically from within PHP by passing "-r
address@domain.com" as the "additional_parameters"
argument to the mail() function (the 5th argument). If
you specify an address both places, the sendmail binary
will be called with two "-r" options, which may have
undefined behavior depending on your sendmail
implementation. With the Postfix MTA, later "-r" options
silently override earlier options, making it possible to
set a global default and still get sensible behavior when
you try to override it locally.

On Windows, the the situation is a lot simpler. The


envelope "from" address there is just the value of
"sendmail_from" in the php.ini file. You can override it
locally with ini_set().

tdaniel at univ dot haifa dot ac dot il 26-Oct-2006 11:17

I had trouble getting multiple emails sent for Outlook


accounts (a single PHP page performed 2 mail() calls).

The PHP mail() function works correctly, but the same


mails that were recieved on a private POP3 server were
randomly missing by our intranet Outlook exchange server.

If you have the same problem, try to verify that the


"Message-ID: " is unique at the $headers string. i.e.

<?php
$headers = [...] .
"Message-ID: <". time() .rand(1,1000). "@".
$_SERVER['SERVER_NAME'].">". "\r\n" [...];
?>

(rand() is used only for demonstration purposes. a better


way is to use an index variable that increments (i++)
after each mail)
I noticed that when multiple messeges were sent
simultaneously, the message-id was the same (probably
there was no miliseconds differential). My guess is that
Outlook is collating messages with the same message-ID; a
thing that causes only one email to pass to the Outlook
inbox instead of a few.

i5513 27-Sep-2006 08:30

[EDITOR's NOTE: Following based off of a note originally


by marcelo dot maraboli at usm dot cl which has been
removed.]

I had a trouble with marcelo' function, I had to add


"$val == 63" condition into "if" sentence for '?'
character

<?php
# From marcelo post:
function encode_iso88591($string)
{
$text = '=?iso-8859-1?q?';

for( $i = 0 ; $i < strlen($string) ; $i++ )


{
$val = ord($string[$i]);
if($val > 127 or $val == 63)
{
$val = dechex($val);
$text .= '='.$val;
}
else
{
$text .= $string[$i];
}

}
$text .= '?=';

return $text;
}

and later use:

// create email
$msg = wordwrap($msg, 70);
$to = "destination@company.com";
$subject = encode_iso88591("hoydía caminé !!");
$headers = "MIME-Versin: 1.0\r\n" .
"Content-type: text/plain; charset=ISO-
8859-1; format=flowed\r\n" .
"Content-Transfer-Encoding: 8bit\r\n" .
"From: $from\r\n" .
"X-Mailer: PHP" . phpversion();

mail($to, $subject, $msg, $headers);


?>

johniskew2 19-Sep-2006 04:28

An important rule of thumb, because it seems few really


follow it and it can alleviate so many headaches: When
filtering your email headers for injection characters use
a regular expression to judge whether the user's input is
valid. For example to see if the user entered a valid e-
mail address use something like [a-zA-Z0-9._%-]+@[a-zA-
Z0-9.-]+\.[a-zA-Z]{2,4}. Dont try to filter out bad
characters (like searching for LF or CR), because you
will ALWAYS miss something. You can be sure your
application is more secure going this route....provided
the regular expression is valid! This same point goes
for any sort of form input not just for sending out
emails.

thomas at p-devion dot de 24-Aug-2006 05:46

Change the function addattachment for multipartmail to


auto detect the mime_content_type ...

<?php
function addattachment($file){
$fname = substr(strrchr($file, "/"), 1);
$data = file_get_contents($file);
$i = count($this->parts);

$content_id = "part$i." . sprintf("%09d", crc32($fname)


) . strrchr($this->to_address,"@");
$this->parts[$i] = "Content-Type:
".mime_content_type($file)."; name=\"$fname\"\r\n" .
"Content-Transfer-Encoding:
base64\r\n" .
"Content-ID:
<$content_id>\r\n" .
"Content-Disposition:
inline;\n" .
" filename=\"$fname\"\r\n" .
"\n" .
chunk_split( base64_encode($data), 68, "\n");
return $content_id;
}
?>

panoramical at gmail dot com 27-Jul-2006 11:19

Searched for ages on the internet trying to find


something that parses EML files and then sends them...for
all of you who want to send an EML files you first have
to upload it, read it, then delete it. Here's my
function...it's specialised for a single form where the
user uploads the EML file.

<?php

if(isset($_POST['submit']))
{

// Reads in a file (eml) a user has inputted


function eml_read_in()
{

$file_ext = stristr($_FILES['upload']['name'], '.');

// If it is an eml file
if($file_ext == '.eml')
{

// Define vars
$dir = 'eml/';
$file = $dir.basename($_FILES['upload']['name']);
$carry = 'yes';

// Try and upload the file


if(move_uploaded_file($_FILES['upload']
['tmp_name'], $file))
{

// Now attempt to read the file


if($eml_file = file($file))
{

// Create the array to store preliminary


headers
$headers = array();
$body = '';
$ii = -1;
// For every line, carry out this loop
foreach($eml_file as $key => $value)
{

$pattern = '^<html>';

if(((eregi($pattern, $value)))||
($carry == 'no'))
{

// Stop putting data into the


$headers array
$carry = 'no';
$i++;
$body .= $value;

else
{

// Separate each one with a colon

if(($eml_file_expl = explode(':', $value))&&($carry ==


'yes'))
{

// The row has been split in


half at least...
if(isset($eml_file_expl[1]))
{

// Put it into the


preliminary headers

$headers[$eml_file_expl[0]] = $eml_file_expl[1];

// There might be more


semicolons in it...
for($i=2;$i<=$count;$i++)
{

// Add the other


values to the header

$headers[$eml_file_expl[0]] .= ':'.$eml_file_expl[$i];
}

// Clear up the headers array


$eml_values = array();
$eml_values[to] = $headers[To];
$eml_values[from] = $headers[From];
$eml_values[subject] = $headers[Subject];
$eml_values['reply-to']
= $headers['Reply-To'];
$eml_values['content-type']
= $headers['Content-Type'];
$eml_values[body] = $body;

unlink($file);

return $eml_values;

else
{

return '<p>File not uploaded - there was an


error</p>';

// Takes information automatically from the $_FILES


array...
$eml_pattern = eml_read_in()
// Headers definable...through eml_read_in() again, but
I'm guessing they'll be the same for each doc...

if(mail($eml_pattern[to], $eml_pattern[subject], $eml_pat


tern[content], $headers)) echo 'Mail Sent';

?>

24-Jul-2006 03:55

correction for class multipartmail

<?php
function addmessage($msg = "", $ctype = "text/plain"){
$this->parts[0] ....
?>

if you are adding attachment first and then addmessage


you can easy overwrite added attachment - better use

<?php

function addmessage($msg = "", $ctype = "text/plain"){


$this->parts[count($this->parts)] ....

?>

sander at cartel dot nl 20-Jul-2006 10:26

I found out that a ms server (ESMTP MAIL Service,


Version: 5.0.2195.6713) also had the problem using CRLF
in the headers:

If messages are not received, try using a LF (\n) only.


Some poor quality Unix mail transfer agents replace LF by
CRLF automatically (which leads to doubling CR if CRLF is
used). This should be a last resort, as it does not
comply with RFC 2822.

The suggested fix works.

Sander

rsjaffe at gmail dot com 21-May-2006 09:10

Here's my way of detecting an attempt to hijack my mail


form.

<?php #requires PHP 5 or greater


$request = array_map('trim',($_SERVER['REQUEST_METHOD']
== "POST") ? $_POST : $_GET) ;

//check for spam injection


$allfields = implode('',$request) ;
$nontext = $request ;
unset($nontext['message'] );
$nontextfields = implode ('',$nontext) ;
if ((strpos ($nontextfields,"\\r")!==false) ||
(strpos ($nontextfields,"\\n")!==false) ||
(stripos ($allfields,"Content-Transfer-Encoding")!
==false) ||
(stripos ($allfields,"MIME-Version")!==false) ||
(stripos ($allfields,"Content-Type")!==false) ||
($request['checkfield']!=$check) ||
(empty($_SERVER['HTTP_USER_AGENT']))) die('Incorrect
request') ; //stop spammers ?>

First, I put the data into an array $request, then set up


two strings: $allfields, which is just all fields
concatenated, then $nontext, which excludes those fields
in which \r\n is allowed (e.g., the message body). Any
form field in which \r\n is allowed should be unset in
the $nontext array before the second implode function (my
message field is called 'message', so I unset that). I
also include a hidden field in the form with a preset
value ('checkfield', $check), so I can see if something
is trying to alter all fields.

This is a combination of a lot of things mentioned in the


messages below...

steve at stevewinnington dot co dot uk 13-Mar-2006 04:24

To all you guys out there having problems with mail


scripts throwing back this (and you know your scripts are
right!!)...

Warning: mail() [function.mail]: "sendmail_from" not set


in php.ini or custom "From:" header missing in:

I had started seeing this after moving some scripts from


4.3 servers to 5.

a dirty get around is using

ini_set ("sendmail_from","a.body@acompany.com");

to force the From header.


Not ideal but it works.
;)

Nimlhug 11-Mar-2006 06:41

As noted in other, well, notes; the "additional headers"


parameter can be easily exploited, when doing things
like:

<?php

mail( $_POST['to'], $_POST['subject'], $_POST['message'],


'Reply-to: '.$_POST['from']."\r\n");
?>

An easy way of fixing this, is removing CRLFs from the


header-strings, like so:

<?php
$_POST['from']
= str_replace( "\r\n", '', $_POST['from'] );
?>

This way, the extra data will be part of the previous


header.

junaid at techni-serve dot com 07-Mar-2006 05:49

Note: on class "multipartmail". Modify the function


buildmessage with the following and it will work great.

function buildmessage(){
$this->message = "This is a multipart message in
mime format.\n";
$cnt = count($this->parts);
for($i=0; $i<$cnt; $i++){
$this->message .= "--" . $this->boundary .
"\n" .$this->parts[$i];
}
$this->message .= "--" . $this->boundary . "--
\n";
}

Thank for all the help.

Ben Cooke 15-Dec-2005 01:34


Note that there is a big difference between the behavior
of this function on Windows systems vs. UNIX systems. On
Windows it delivers directly to an SMTP server, while on
a UNIX system it uses a local command to hand off to the
system's own MTA.

The upshot of all this is that on a Windows system your


message and headers must use the standard line endings
\r\n as prescribed by the email specs. On a UNIX system
the MTA's "sendmail" interface assumes that recieved data
will use UNIX line endings and will turn any \n to \r\n,
so you must supply only \n to mail() on a UNIX system to
avoid the MTA hypercorrecting to \r\r\n.

If you use plain old \n on a Windows system, some MTAs


will get a little upset. qmail in particular will refuse
outright to accept any message that has a lonely \n
without an accompanying \r.

fnjordy at gmail dot com 05-Oct-2005 09:54

Another example of sending a utf-8 HTML mail:

<?php
$to = 'bob@example.com';
$subject = 'Wakeup bob!';
$message = '<b>yo</b>, whassup?';
$headers = "From: server@example.com\r\n" .
'X-Mailer: PHP/' . phpversion() . "\r\n" .
"MIME-Version: 1.0\r\n" .
"Content-Type: text/html; charset=utf-8\r\n" .
"Content-Transfer-Encoding: 8bit\r\n\r\n";

// Send
mail($to, $subject, $message, $headers);
?>

fontajos at phpeppershop dot com 21-Sep-2005 03:24

Problems with Microsoft Exchange and PHP as ISAPI-module

We found out, that if you want to send multipart mime


emails using the PHP mail-function on a Windows box using
a Microsoft Exchange server, you have to use separate
containers for the mail body and the mail header.

In many examples like


in http://www.zend.com/zend/trick/html-email.php or in
the book PHP developers cookbook you find html
multipart/alternative mailing solutions that build the
mime header and the mail body into one PHP variable and
send this as fourth argument (header) to the PHP mail-
function. This works fine on most systems but not on the
above mentioned combination.

We found a rather trivial solution: Simply split the mime


mail header and the mail body into two separate variables
and give them separately to the PHP mail function,
example:

<?php
//add From: header
$headers = "From: webserver@localhost\r\n";

//specify MIME version 1.0


$headers .= "MIME-Version: 1.0\r\n";

//unique boundary
$boundary = uniqid("HTMLDEMO");

//tell e-mail client this e-mail contains//alternate


versions
$headers .= "Content-Type: multipart/mixed; boundary =
$boundary\r\n\r\n";

//plain text version of message


$body = "--$boundary\r\n" .
"Content-Type: text/plain; charset=ISO-8859-1\r\n" .
"Content-Transfer-Encoding: base64\r\n\r\n";
$body .= chunk_split(base64_encode("This is the plain
text version!"));

//HTML version of message


$body .= "--$boundary\r\n" .
"Content-Type: text/html; charset=ISO-8859-1\r\n" .
"Content-Transfer-Encoding: base64\r\n\r\n";
$body .= chunk_split(base64_encode("This the <b>HTML</b>
version!"));

//send message
mail("root@localhost", "An HTML
Message", $body, $headers);
?>

GwarDrazul 15-Sep-2005 11:01

The article mentioned below is quite good to understand


the problem of header injection. However, it suggests the
following as a solution: look for "\n" and "\r" inside
your user input fields (especially in those used for the
$header param) and, if found reject the mail.

Allthough this will probably work I still believe it is


better to have a "white list" of allowed characters
instead of a "black list" with forbidden characters.

Example:
If you want a user to enter his name, then allow
characters only!
If you want a user to enter his email adress, then check
if the entry is a valid email adress.

Doing so might automatically solve problems which you


didn't think of when you created the "black list". For
SMTP headers colons are needed. If you check for a valid
email adress the hacker won't be able to enter colons
inside that form field.

I suggest using regular expressions for those checks.

For more information about regular expressions see:


http://www.regular-expressions.info/

javier at zincro dot com 31-May-2005 04:48

This might be something obvious, but it gave me a lot of


headache to find out:

If you use an ascii char#0 in the "string mensaje"


parameter, it will truncate the message till that point,
(this happened to me sending a message read from a file)

For example:

<?php
$hs_email="blabla@blabla.com";
$hs_asunto="a message for you";

$hs_contenido="beginofcontent_";
$hs_contenido.=chr(0);
$hs_contenido.="_endofcontent";

mail($hs_email,$hs_asunto,$hs_contenido);
?>

Will result in an email that only contains the string:


beginofcontent_

Anyway, just in case it can save someone some time...

msheldon at desertraven dot com 15-May-2005 07:09

Just a comment on some of the examples, and as a note for


those who may be unaware. The SMTP RFC 822 is VERY
explicit in stating that \r\n is the ONLY acceptable line
break format in the headers, though is a little vague
about the message body. While many MTAs will deal with
just \n, I've run accross plenty of them that will
exhibit "interesting" behaviours when this happens. Those
MTAs that are strict in compliance will definitely break
when header lines are terminated with only \n. They will
also most likely break if the body of the message
contains more than 1000 consecutive characters without
a \r\n.*

Note that RFC 821 is a little more clear in defining:


"line
A a sequence of ASCII characters ending with a
<CRLF>."

RFC 821 makes no distinction between header lines and


message body lines, since both are actually transmitted
during the DATA phase.

Bottom line, best practice is to be sure to convert any


bare \n characters in the message to \r\n.

* "The maximum total length of a text line including the


<CRLF> is 1000 characters" (RFC 821)

jonte at macnytt dot com 24-Apr-2005 11:16

Users of Mac OS X Server need to activate SMTP part of


the Mailserver before this is working.

Also note that if the ISP has blocked port 25 outgoing,


you run into problems. You can find more info about this
in the SMTP server log in Server Admin application if you
run OSX Server.

18-Apr-2005 07:20

A co-worker of mine had a problem where she needed to


have a backslash in the header. Basically, the name of
the company has a couple of backslashes in it. However,
when the recipient was receiving the email, the "From:"
part had the backslashes removed. We got it to work but
placing three backslashes whenever we wanted one to show
up. I'd assume that the mail server was modifying the
headers and this is not really an issue with php. Anyway,
thought this might help someone.

benles at bldigital dot com 21-Mar-2005 05:47

I get a 550 error when using mail() with this To format:

User <user@example.com>

When it's changed to just the bare email, it works fine.


Just FYI that some mail servers may behave this way.

php dot net at schrecktech dot com 03-Mar-2005 12:07

When sending MIME email make sure you follow the


documentation with the "70" characters per line...you may
end up with missing characters...and that is really hard
to track down...

jdephix at hotmail dot com 02-Mar-2005 08:25

How to add multiple attachment to an email:

An email can be split into many parts separated by a


boundary followed by a Content-Type and a Content-
Disposition.

The boundary is initialized as follows:


<?php
$boundary = '-----=' . md5( uniqid ( rand() ) );
?>

You can attach a Word document if you specify:


<?php
$message .= "Content-Type: application/msword; name=\"my
attachment\"\n";
$message .= "Content-Transfer-Encoding: base64\n";
$message .= "Content-Disposition: attachment;
filename=\"$theFile\"\n\n";
?>

When adding a file you must open it and read it with


fopen and add the content to the message:
<?php
$path = "whatever the path to the file is";
$fp = fopen($path, 'r');
do //we loop until there is no data left
{
$data = fread($fp, 8192);
if (strlen($data) == 0) break;
$content .= $data;
} while (true);
$content_encode = chunk_split(base64_encode($content));
$message .= $content_encode . "\n";
$message .= "--" . $boundary . "\n";
?>

Add the needed headers and send!


<?php
$headers = "From: \"Me\"<me@example.com>\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/mixed;
boundary=\"$boundary\"";
mail('myAddress@example.com', 'Email with attachment from
PHP', $message, $headers);
?>

Finally, if you add an image and want it displayed in


your email, change the Content-Type from attachment to
inline:

<?php
$message .= "Content-Disposition: inline;
filename=\"$theFile\"\n\n";
?>

Enjoy!

grey at greywyvern dot moc 18-Feb-2005 08:47

When including your own custom headers try not to include


a trailing \r\n at the end of the last header. Leaving
the \r\n causes an extra line-feed at the beginning of
the message body, so your message will start on the
second line.

Sven Riedel 10-Jul-2004 01:22

mail() requires /bin/sh to exist in Unix environments,


next to a mail delivery program. This is very relevant
when setting up apache in a chroot environment.
Unfortunately this isn't anywhere in the documentation
and took me several months to figure out.
nospam at mingo dot ath dot cx 09-May-2004 01:55

If you're using a linux server using Postfix, and your


server hasn't the host name set to a valid name (because
it's behind a firewall in an intranet), it's possible
that when sending mails using the mail function, some
mail servers reject them. This is because they can't
check the return path header. If you want to change the
Return-Path used by sendmail init the php.ini and edit
the sendmail_path variable to this:

sendmail_path = "sendmail -t -i -F webmaster@yoursite.com


-f webmaster@yoursite.com"

Paul 25-Feb-2004 10:51

My mime multipart/alternative messages were going ok,


until I switched to qmail with php .. after years of
painfull searching, I came across this on the Life With
Qmail 'Gotchas' section:

G.11. Carriage Return/Linefeed (CRLF) line breaks don't


work

qmail-inject and other local injection mechanisms like


sendmail don't work right when messages are injected with
DOS-style carriage return/linefeed (CRLF) line breaks.
Unlike Sendmail, qmail requires locally-injected messages
to use Unix newlines (LF only). This is a common problem
with PHP scripts.

So now, I can go back to sending emails with text AND


html components :)

roberto dot silva at mexicoshipping dot net 24-Jan-2004


12:16

If you can't use or don't understand how to use the


sendmail program from linux, you can use a PEAR object to
send mail.

<?php
include("Mail.php");

$recipients = "mailto@example.com";

$headers["From"] = "mailfrom@example.com";
$headers["To"] = "mailto@example.com";
$headers["Subject"] = "Test message";
$body = "TEST MESSAGE!!!";

$params["host"] = "example.com";
$params["port"] = "25";
$params["auth"] = true;
$params["username"] = "user";
$params["password"] = "password";

// Create the mail object using the Mail::factory method


$mail_object =& Mail::factory("smtp", $params);

$mail_object->send($recipients, $headers, $body);


?>

In my case, i use a smtp server that require


authentication, and sendmail configuration is almost
cryptic to me.

PEAR is already installed in PHP 4.0.3 , if not, you must


go to http://pear.php.net/ and install it, in my case, I
needed to add the Socket.php to the PEAR library.

f dot touchard at laposte dot net 31-Jan-2003 03:46

***Encoding plain text as quoted-printable in MIME


email***

If you don't want to install IMAP and use imap_8bit() to


encode plain text or html message as quoted-printable
(friendly french special characters encoding :-) in MIME
email, try this function.
I haven't fully tested it ( like with microtime with long
mails). I send html message as 7-bit, so I didn't try yet
with html.
If you have good html practise, you don't really need to
encode html as quote-printable as it only uses 7-bit
chars.
F.Touchard

<?php
function qp_encoding($Message) {

/* Build (most polpular) Extended ASCII Char/Hex MAP


(characters >127 & <255) */
for ($i=0; $i<127; $i++) {
$CharList[$i] = "/".chr($i+128)."/";
$HexList[$i]
= "=".strtoupper(bin2hex(chr($i+128)));
}

/* Encode equal sign & 8-bit characters as equal


signs followed by their hexadecimal values */
$Message = str_replace("=", "=3D", $Message);
$Message = preg_replace($CharList, $HexList, $Message
);

/* Lines longer than 76 characters (size limit for


quoted-printable Content-Transfer-Encoding)
will be cut after character 75 and an equals sign
is appended to these lines. */
$MessageLines = split("\n", $Message);
$Message_qp = "";
while(list(, $Line) = each($MessageLines)) {
if (strlen($Line) > 75) {
$Pointer = 0;
while ($Pointer <= strlen($Line)) {
$Offset = 0;
if (preg_match("/^=(3D|([8-9A-F]{1}[0-9A-
F]{1}))$/", substr($Line, ($Pointer+73), 3))) $Offset=-
2;
if (preg_match("/^=(3D|([8-9A-F]{1}[0-9A-
F]{1}))$/", substr($Line, ($Pointer+74), 3))) $Offset=-
1;
$Message_qp.= substr($Line, $Pointer,
(75+$Offset))."=\n";
if ((strlen($Line) - ($Pointer+75))
<= 75) {
$Message_qp.= substr($Line,
($Pointer+75+$Offset))."\n";
break 1;
}
$Pointer+= 75+$Offset;
}
} else {
$Message_qp.= $Line."\n";
}
}
return $Message_qp;
}
?>

gordon at kanazawa-gu dot ac dot jp 29-Dec-2002 02:04

If your server doesn't have mb_send_mail() enabled but


you want to use non-ascii (multi-byte) chars in an
email's subject or name headers, you can use something
like the following:
<?php
$charset = "iso-2202-jp"; // japanese
$to = encode("japanese name 01", $charset) . "
<to@email.com>";
$from = encode("japanese name 02", $charset) . "
<from@email.com>";
$subject = encode("japanese text");
$message = "does not need to be encoded";
mail($to, $subject, $message, $from);

function encode($in_str, $charset) {


$out_str = $in_str;
if ($out_str && $charset) {

// define start delimimter, end delimiter and


spacer
$end = "?=";
$start = "=?" . $charset . "?B?";
$spacer = $end . "\r\n " . $start;

// determine length of encoded text within


chunks
// and ensure length is even
$length = 75 - strlen($start) - strlen($end);

/*
[EDIT BY danbrown AT php DOT net: The
following
is a bugfix provided by (gardan AT gmx DOT
de)
on 31-MAR-2005 with the following note:
"This means: $length should not be even,
but divisible by 4. The reason is that in
base64-encoding 3 8-bit-chars are
represented
by 4 6-bit-chars. These 4 chars must not be
split between two encoded words, according
to RFC-2047.
*/
$length = $length - ($length % 4);

// encode the string and split it into chunks


// with spacers after each chunk
$out_str = base64_encode($out_str);

$out_str = chunk_split($out_str, $length, $spacer);


// remove trailing spacer and
// add start and end delimiters
$spacer = preg_quote($spacer);

$out_str = preg_replace("/" . $spacer . "$/", "", $out


_str);
$out_str = $start . $out_str . $end;
}
return $out_str;
}
// for details on Message Header Extensions
// for Non-ASCII Text see ...
// http://www.faqs.org/rfcs/rfc2047.html

?>

stevenlim at Edinburgh-Consulting dot com 06-Sep-2002


07:53

How to detect a bounce email

1. make sure the email you send out have the header
"Return-Path: detect-bounce@example.com\r\n",
&
"Return-Receipt-To: bounce@example.com\r\n"

2. setup this detect-bounce mail account at your mail


server

3. redirect the incoming mail from this email account to


your php script (check your mail server doc on how do
this)

4. your php script will then be able to process the


incoming email in whatever way you like, including to
detect bounce mail message (use regexp search).

Note that the mail will be not be store after the mail
server has redirect to your script. If you want to store
it, you need additional code in your script

Hope the above help

Steven Lim
IT Consultant (www.Edinburgh-Consulting.com)

add a note

You might also like