Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Topics

Recent Status Updates

View All Updates

Photo
- - - - -

Sending Emails With Sendmail - Part 2

form sendmail

  • Please log in to reply
7 replies to this topic

#1 dargueta

dargueta

    I chown trolls.

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

Posted 31 August 2009 - 04:55 PM

Ok, so now that you know how to use sendmail to send basic text emails, it's time to move on to something more interesting. Because sending HTML emails will inevitably require embedding images and other stuff, I'll teach you how to add attachments first.

Let's say we're working on a project with our friend Bob, and we want to share some files with him, foo.c and readme.txt. But how...

As I stated in my earlier tutorial, the purpose of the MIME headers is to indicate type information about what you're sending. Unfortunately there's no I-Am-An-Attachment header, but there are a few headers we can use in combination to get the desired effect. Take a look:

To: "Bob" <bob@yahoo.com>
From: "Me" <me@codecall.net>
Subject: Source Code
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="FILEBOUNDARY"

Wait...what?! What happened to text/plain? Well, we need to tell the mail server that we're sending an email with more than one part, i.e. the message and some attachments. Because the server has no way of knowing how long each of the parts are, we pass the boundary argument. We will have to stick this in between every part of the message, on its own line, preceded by two dashes. The end of the message must have the boundary marker, but with two dashes at the end as well:

--BOUNDARY
blah blah part one
--BOUNDARY
blah blah part two
--BOUNDARY
blah blah last part...
--BOUNDARY--

Your mail client (i.e. Gmail, Yahoo, etc.) will a much longer and more random boundary marker, like --smtp.yahoo.com-dargueta-310820091952GMT-5--. Why? Well, imagine if one of the files I'm sending just happens to contain the text --BOUNDARY on a line by itself. Oops. The mail server is going to interpret that as the end of the file...and that'll screw everything else up. Better to have a ridiculous boundary that no one is going to read anyway than to have a simple one and run the risk of messing up the message.
Wait, we're not done yet...immediately after each boundary marker (except the last one indicating the end of the message, of course) we have to declare the type of the part we're sending. In this case, it'll be text/plain for each of our parts since we're sending just plain text files. We also need to add a header declaring each part as either an attachment or part of the message text that Bob is going to read, like so:

Message body:
--FILEBOUNDARY
Content-Type: text/plain
Content-Disposition: inline

Hello, World!

Attachment:
--FILEBOUNDARY
Content-Type: text/plain
Content-Disposition: attachment; filename="whatever.txt"

Some text file containing unimportant stuff here.
.
**...sendmail might choke on that...we'll have
to make sure to pass -i to avoid this problem.

Notice that again, we have to leave a blank line to signal the end of the headers. Putting it all together, here's our final email:

To: "Bob" <bob@yahoo.com>
From: "Me" <me@codecall.net>
Subject: Source Code
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="FILEBOUNDARY"

--FILEBOUNDARY
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline

Hello, World!
--FILEBOUNDARY
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: attachment; filename="foo.c"

#include <stdio.h>
int main(void) {
printf("Hello, World!\n");
return 0;
}

--FILEBOUNDARY
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: attachment; filename="readme.txt"

This is a program that prints "Hello, World!" to the console and exits.
--FILEBOUNDARY--

I slipped in something extra--did you notice the charset=iso-8859-1 parameter? It tells the email client what character set to use to render the text. If I were sending text in Russian, for example, I could put UTF-8, which is one of the most widely supported Unicode formats. It's always good practice to put this parameter in, otherwise the client will use the user's preferred setting - and that can cause problems. Say someone in China decides to send me a text file. They may write it with the Latin alphabet, but since their default encoding is UTF-8 and mine is ISO 8859-1, I'm going to see a bunch of garbled symbols. So always specify your character set.

Now, let's say we want to send Bob a different kind of file - a binary file. Say a .tar.gz. Clearly we're going to have problems here...binary doesn't transfer well because many systems truncate bytes to 7 bits. Why, I don't know. But - happily, we have a way around this, called base-64 encoding. By using only the characters 'a'-'z', 'A'-'Z', '0'-'9', '+', and '/' ('=' is used in special cases as well), you can encode anything. Think of it like hexadecimal, except base-64 and not base-16. Luckily, *NIX systems come with a utility to help us in our quest. First thing we need to do is encode our file:

diarguet@rtp-lds-035:~$ cat myarchive.tar.gz | uuencode -m /dev/stdout > myencodedarchive.base64

Ugly, I know, but for some reason I can't get it to work any other way. uuencode also has an annoying habit of sticking this begin base64 ... line at the beginning, so make sure to remove that first line before you put it in your email. If you open your file, you should get something frightening, like this:

R0lGODlhEgATAJEAAAAAAP///wCZAP///yH5BAEAAAMALAAAAAASABMAAAIo
jI+pGyK8nINqUiTfbVnfvHEg1UmhdZRqaawu6XZVjKb0/CYxo8JOAQA7
====

If I typed that right, it should be a little GIF image of a tree. Great! So now we've got our archive all nice and encoded...now what? Well, we need a MIME type for this. Er...well, we can look at the IANA list of all MIME types and find the appropriate type with some work, or we can look at this list that lists MIME types by file extension. Note that it's not complete and some of the extensions may not be listed. For those that aren't, you'll have to make the judgment yourself. In this case, since we're using a .tar.gz file, we want application/x-compressed. So, off we go:

--FILEBOUNDARY
Content-Type: application/x-compressed; charset=iso-8859-1
Content-Disposition: attachment; filename="myarchive.tar.gz"
Content-Transfer-Encoding: base64

jdaia89UJU4VEWQ+JAOISP90JCDmlagnkjznckjdzn and so on...

Note the new header: Content-Transfer-Encoding. We need to put this for anything that doesn't have a MIME type starting with text/, because that means it's probably binary, and there are several different ways of encoding binary data.

Putting it all together, we get:

To: "Bob" <bob@yahoo.com>
From: "Me" <me@codecall.net>
Subject: Archived data
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="FILEBOUNDARY"

--FILEBOUNDARY
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline

Hello, World!
--FILEBOUNDARY
Content-Type: application/x-compressed; charset=iso-8859-1
Content-Disposition: attachment; filename="myarchive.tar.gz"
Content-Transfer-Encoding: base64

jdaia89UJU4VEWQ+JAOISP90JCDmlagnkjznckjdzn...
--FILEBOUNDARY--

There we go! Now you can send text emails with attachments to all your family and friends. I think this tutorial has gone long enough, so I'll get to HTML emails and embedding stuff in the next tutorial.

Missed part 1? Click here to go back.
  • 2

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


#2 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 01 September 2009 - 04:27 AM

These almost look like tutorials on the mail format.
  • 0

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

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


#3 dargueta

dargueta

    I chown trolls.

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

Posted 01 September 2009 - 04:30 AM

Well, you kind of have to know the mail format to send an email...
  • 0

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


#4 Guest_Jordan_*

Guest_Jordan_*
  • Guest

Posted 01 September 2009 - 05:18 AM

Good tutorial, +rep.
  • 0

#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 01 September 2009 - 09:50 AM

True. Many of our technologies depend on the protocols.
  • 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
  • 4856 posts
  • Programming Language:C, Java, C++, PHP, Python, JavaScript, Perl, Assembly, Bash, Others
  • Learning:Objective-C

Posted 01 September 2009 - 02:27 PM

Do you think this should be in the General Programming section? I kinda meant it for PHP / Perl / anything else that uses sendmail, but since it was a CLI utility I decided to stick it here.
  • 0

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


#7 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 02 September 2009 - 01:10 PM

It works as is.
  • 0

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

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


#8 dargueta

dargueta

    I chown trolls.

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

Posted 02 September 2009 - 01:46 PM

Ok, good. I'll probably post part three today, I think.
  • 0

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






Also tagged with one or more of these keywords: form, sendmail

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download