Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Sending Emails With Sendmail - Part 3

sendmail

  • Please log in to reply
6 replies to this topic

#1 dargueta

dargueta

    I chown trolls.

  • Moderator
  • 4854 posts
  • Programming Language:C, Java, C++, PHP, Python, JavaScript, Perl, Assembly, Bash, Others
  • Learning:Objective-C

Posted 02 September 2009 - 08:24 PM

Warning: You probably will be lost if you haven't read the previous two tutorials on this.

Sending Pure HTML
So now that you know how to add attachments and all that fun stuff, I'm now going to teach you how to send HTML emails. It's rather simple if you're not embedding images and stuff like that. All you have to do is change the Content-Type header from text/plain to text/html. So a potential content type line would look like this:

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

(Of course, you'd put the appropriate character set for whatever it is that you're doing.)

Now you can put HTML in your message body, and the mail client will probably handle it appropriately. To deal with situations where it won't, keep reading and I'll show you how to handle it.

Embedding Images and Other Files
But what if you have an image? Well, there are two ways of doing it. One is to provide a web URL for the image source:

<img src="http://forum.codecall.net/images/misc/navbit.gif" />

This is called "lazy HTML." The problem with this is that most modern email clients, for security reasons, will block such images. Why? Well, let's say a spammer sends you an email with a picture linked from site X. Your browser, while rendering the email, sees that there's a picture in the body and asks the server for X to send it over. Now the spammer not only knows your email address, he/she has your IP address too. It's better to send the image as an attachment. We know how to send attachments...but how do we reference it in the HTML? Aha. Well, there's a slight modification we have to make to the attachment.

Here are the headers as if we were just sending a GIF as a plain attachment:
Content-Type: image/gif
Content-Disposition: attachment; filename="mygif.gif"
Content-Transfer-Encoding: base64

And here are the headers for sending the same file in an HTML email:
Content-Type: image/gif
Content-Disposition: inline; filename="mygif.gif"
Content-Id: <mygif>
Content-Transfer-Encoding: base64

Notice two things:
1) The Content-Disposition header changed from attachment to inline. This is necessary if we want the image to show up as part of the HTML body and not as just a regular attachment.
2) We added another header: Content-Id. This is what we're going to use to reference the image in the body of our HTML. Yes, the angle brackets are required. You can't have any spaces or weird characters like / and \. Just keep it to alphanumeric, underscores, and dashes, and you'll never go wrong.

To use the image in our HTML, we would do this:

<img src="cid:mygif" />

cid, as you probably guessed, is short for Content Id. You can extend this to anything you reference in your HTML: Javascript files, CSS, other HTML files...basically anything in a regular website. Just remember that:
1) Most systems restrict email sizes to about 20 megabytes.
2) Active content, i.e. Javascript, will probably be blocked by Outlook and other email clients. At the very least your recipient will get that little bar at the top saying "Explorer has blocked this page from displaying active content..." or something similar.

I've read that you can also do forms and use a mailto: link to submit it, but somehow I think that a lot of clients will also block this behavior, as it's a possible security hole. Don't count on it.

Catering To Everyone
This is not so much the case nowadays as ten years ago, but there are still people who don't like receiving HTML emails, or can't display them. How are we going to ensure that they get a nicely formatted email, instead of just seeing the raw HTML? Remember the multipart-mixed content type? Well, we're going to use it again. The first part of our email is going to be of type multipart/alternative; that part is further subdivided into two other parts, the HTML version first, and the plain text version second. (And yes, you need another unique boundary token.)

...headers go here...
Content-Type: multipart/mixed; boundary="FILEBOUNDARY"

--FILEBOUNDARY
Content-Type: multipart/alternative; boundary="MSGBOUNDARY"

--MSGBOUNDARY
Content-Type: text/html; charset=iso-8859-1
Content-Disposition: inline

<html>
    <body>
        This is the HTML version of the email. Always
        put this first, because browsers will display the
        first part that they're capable of displaying
        and ignore the rest.
    </body>
</html>
--MSGBOUNDARY
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline

This is the plain text email. Always put this second,
otherwise browsers will show this first and not your
HTML, even if they can display it.
--MSGBOUNDARY--
--FILEBOUNDARY
...embedded images and other things here...
--FILEBOUNDARY--

So we have to declare two boundary tokens now, with the same rules as before. Pretty straightforward.

Putting It All Together
All right...let's send our friend Bob an email with HTML, a text version if for some reason he can't view the HTML, a picture, and a file attachment. (And we're going to CC a few friends for fun.)

To: "Bob" <bob@yahoo.com>
Cc: mary@hotmail.com; fulano@gmail.com; jane@austen.net
From: "Me" <me@codecall.net>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="FILEBOUNDARY"

--FILEBOUNDARY
Content-Type: multipart/alternative; boundary="MSGBOUNDARY"

--MSGBOUNDARY
Content-Type: text/html; charset=iso-8859-1
Content-Disposition: inline

<html>
    <body>
        Hello, World!<br/>
        <img src="cid:hello" alt="Hello Image"/>
    </body>
</html>
--MSGBOUNDARY
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline

Hello, World!
[you're missing out on an image here]
--MSGBOUNDARY--
--FILEBOUNDARY
Content-Type: image/jpeg
Content-Disposition: inline; filename="hello.jpg"
Content-Transfer-Encoding: base64
Content-Id: <hello>

j8SAoi9dxzDF+JIO3PoooASCODN
...you get the idea...
--FILEBOUNDARY
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: attachment; filename="hello.c"

#include <stdio.h>

int main(void) {
    printf("Hello, World!\n");
    return 0;
}
--FILEBOUNDARY--

Other Cool Stuff
This is for those of you that're really interested...here are some of the more common additional headers. There are a lot more specified in RFC 4021 that you can use, complete with explanations and guidelines on how to use them.

Redirecting Responses
When the recipient hits "Reply", this email address will be put in the To: field instead of whatever was in the From: field. Useful for redirecting responses to your boss. Note that this field can only take one email address.

Reply-To: youremail@host.com

Starting A Thread
You know how when someone responds to your email, your client will put it right next to your original email? It doesn't do it by looking at the subject line. Instead, it matches this field:

Message-Id: some-unique-string_09-03-2009-0000_gmt--5_rtp-lds-035_dargueta

Replying To A Thread
If you're fortunate enough to receive an email with the Message-Id field set, you can set this field to the Message Id to cause you recipient's client to treat your message as a reply, regardless of the subject line.

In-Reply-To: some-unique-string_09-03-2009-0000_gmt--5_rtp-lds-035_dargueta

Forwarding Emails
You can set this field if you want so that people replying to this forwarded email will be treated as replying to the original, not your forwarded message.

Original-Message-Id: some-unique-string_09-03-2009-0000_gmt--5_rtp-lds-035_dargueta

Setting The Date
When the message was sent.

Date: day-of-week, day month year time-of-day timezone
day-of-week = Mon | Tue | Wed | Thu | Fri | Sat | Sun
day = 1-31
month = Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec
year = yyyy
time-of-day = hh:mm(:ss) (seconds are optional)
timezone = e.g. -0500 for Eastern Standard Time, -0800 for Pacific Standard Time, etc.

Further Reading
RFC 2822 - Internet Message Format
MIME Types By File Extension (Note this is not a complete list)

Edited by dargueta, 03 September 2009 - 10:15 AM.

  • 2

sudo rm -rf / && echo $'Sanitize your inputs!'


#2 Guest_Jordan_*

Guest_Jordan_*
  • Guest

Posted 03 September 2009 - 04:13 AM

Very well done! +rep
  • 0

#3 WingedPanther73

WingedPanther73

    A spammer's worst nightmare

  • Moderator
  • 17757 posts
  • Location:Upstate, South Carolina
  • Programming Language:C, C++, PL/SQL, Delphi/Object Pascal, Pascal, Transact-SQL, Others
  • Learning:Java, C#, PHP, JavaScript, Lisp, Fortran, Haskell, Others

Posted 03 September 2009 - 04:58 AM

Nice job. I always send email as plain text, just in case. Some of my customers have VERY old systems. +rep
  • 0

Programming is a branch of mathematics.
My CodeCall Blog | My Personal Blog

My MineCraft server site: http://banishedwings.enjin.com/


#4 dargueta

dargueta

    I chown trolls.

  • Moderator
  • 4854 posts
  • Programming Language:C, Java, C++, PHP, Python, JavaScript, Perl, Assembly, Bash, Others
  • Learning:Objective-C

Posted 03 September 2009 - 05:11 AM

Hm...it appears that my Mary, **** and Jane example failed.

EDIT: And here it failed again.
  • 0

sudo rm -rf / && echo $'Sanitize your inputs!'


#5 WingedPanther73

WingedPanther73

    A spammer's worst nightmare

  • Moderator
  • 17757 posts
  • Location:Upstate, South Carolina
  • Programming Language:C, C++, PL/SQL, Delphi/Object Pascal, Pascal, Transact-SQL, Others
  • Learning:Java, C#, PHP, JavaScript, Lisp, Fortran, Haskell, Others

Posted 03 September 2009 - 07:09 AM

You mean Richard?
  • 0

Programming is a branch of mathematics.
My CodeCall Blog | My Personal Blog

My MineCraft server site: http://banishedwings.enjin.com/


#6 dargueta

dargueta

    I chown trolls.

  • Moderator
  • 4854 posts
  • Programming Language:C, Java, C++, PHP, Python, JavaScript, Perl, Assembly, Bash, Others
  • Learning:Objective-C

Posted 03 September 2009 - 10:14 AM

Yes. The typical names used when teaching English grammar.
  • 0

sudo rm -rf / && echo $'Sanitize your inputs!'


#7 Guest_Jordan_*

Guest_Jordan_*
  • Guest

Posted 03 September 2009 - 05:41 PM

My middle name is Richard, ****.
  • 0





Also tagged with one or more of these keywords: sendmail