Click here to Skip to main content
Click here to Skip to main content

A class for sending emails with attachments in C#.

By , 28 Feb 2003
 

Introduction

This is a SMTP client implementation in C#. It handles attachments and sending the body as HTML. It can also do basic (AUTH LOGIN PLAIN) and Base64 (AUTH LOGIN) authentication.

A little while back, I went looking for a (free) class/library to send email with in C#. I found several examples, but none fit my needs. They mostly demonstrated the basics and did not get into attachments. So, I decided to write my own implementation.

I reviewed several RFCs (821,822 mostly) and set about the task. The initial process was pretty straight forward and proved a good lesson in Tcp communication in C#. The attachment process was a little confusing. I understood how to do what I needed to, but was unsure of exactly what, and in what order, to do. The RFC for that and the MIME related ones aren't exactly crystal clear. That's when I found PJ Naughter's CSMTPConnection class. His implementation helped me to see the correct sequencing/structure of the MIME parts and was overall very useful. The version on The Code Project is a little old however, I would recommend getting it from PJ's site. Many thanks to him for a great example.

There is a second project in the solution which is a basic email form that uses this class.

The main class can be used as follows

Example usage of class:

SmtpEmailer emailer = new SmtpEmailer();
emailer.Host = "mymail.host.com";			
emailer.From = "someone@somwhere.com";
emailer.AuthenticationMode = AuthenticationType.Base64;
emailer.User = "myuserid";
emailer.Password = "mypassword";
emailer.Subject = "a test message";
emailer.Body = "this is only a test";
emailer.To.Add("toperson1@nowhere.com");
emailer.To.Add("toperson2@nowhere.com");
emailer.Attachments.Add(new SmtpAttachment(@"c:\file1.exe"));
emailer.Attachments.Add(new SmtpAttachment(@"c:\file2.txt"));      
emailer.SendMessage();

You can also send the body as HTML and include inline images by adding:

emailer.SendAsHTML = true;

When you send as HTML and you want to include images inline in the HTML, you would add the attachment as follows:

emailer.Attachments.Add(new SmtpAttachment(@"c:\mypicture.jpg", 
                        "image/jpg", AttachmentLocation.Inline));

The image will be given an ID that is it filename without extension. You then refer to the image in the html as

 <img src="cid:MY_FILENAME_WITHOUT_EXTENSION">

There is also an event, OnMailSent for use with the SendMessageAsync method. If people find this useful, then I will post updates/enhancements along the way. Enjoy.

Version History

1.4 - Added plain text (AUTH LOGIN PLAIN) and base64 (AUTH LOGIN) authentication.
Added CC/BCC properties.

1.3 - Fixed MIME header sequences and several issues with Outlook vs Outlook Express.

1.2 - Fixed quoted-printable encoding problem and an issue with Outlook.

1.1 - Added HTML body support, better MIME handling.

1.0 - Initial release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Steaven Woyan
Web Developer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generaldate Header problem with not en-US countrymemberfravelgue8 Nov '10 - 23:12 
You could have some problems with mail clients, if sent date is not in en-US format.
Questiongreat work but what about SSL?memberAdore C++13 Jun '09 - 6:32 
dear sir ,
 
how to make ur class support SSL ?? (STARTTLS (some clients call this SSL) ) ??
 
thanks alot bye
Generalproblems in sending emailsmemberammartahan16 Jul '06 - 3:29 
Hello all,
 
I did try, and I always get a success in email sending, but I never received the sent email.
 
I tried to send within the same domain and I succeeded, but when I send from a domain to an external email, I never receive it!
 
example:from name1@domain1.com to name2@domain2.com (name2 never receives anything).
But from name1@domain.com to name2@domain.com (success)
 
Any Ideas why?
 

 
wishes
 
Joe
GeneralRe: problems in sending emailsgroupMihaiPopescu4 Jul '10 - 20:52 
it is a lag between servers, you should wait, the email will come...
Generalembedding images (inline images)memberrocder10 Jul '06 - 2:40 
hi,
 
i am trying to send out newsletters with the images embedded on to the email
 
i am able to do it manually by pasting it on to the outlook client (pasting it and not attaching it)
 
however i want to do it with the help of asp.net and that is what got me on this page
 
here is the code i have written
 
Tabs4u.SmtpEmailer emailer = new Tabs4u.SmtpEmailer();
emailer.Host = "XXX.XXX.XXX";
emailer.From = "XXX@XXX.XXX";
emailer.AuthenticationMode = Tabs4u.AuthenticationType.Base64;
emailer.User = "XXX@XXX.XXX";
emailer.Password = "XXX";
emailer.Subject = "dynammic mail from asp.net";
emailer.Body = "<html><head><title>newsletter</title><meta http-equiv='Content-Type' content='text/html; charset=iso-8859-1'></head><body bgcolor='#FFFFFF' leftmargin='0' topmargin='0' marginwidth='0' marginheight='0'><!-- ImageReady Slices (newsletter.psd) -->
<img src='SMS_mailer5.jpg' width='600' height='1000'>
<!-- End ImageReady Slices --></body></html>";
emailer.To.Add("XXX@XXX.XXX");
emailer.To.Add("XXX@XXX.XXX");
emailer.Attachments.Add(new Tabs4u.SmtpAttachment(@"C:\SMS_mailer5.jpg", "image/jpg", Tabs4u.AttachmentLocation.Inline));
//emailer.Attachments.Add(new Tabs4u.SmtpAttachment(@"c:\file1.exe"), "image/jpg", Tabs4u.AttachmentLocation.Inline);
//emailer.Attachments.Add(new Tabs4u.SmtpAttachment(@"c:\file2.txt"), "image/jpg", Tabs4u.AttachmentLocation.Inline);
emailer.SendAsHtml = true;
 
emailer.SendMessage();
 
i do get an email, however the image is in the form of attachments and there is no HTML pages displayed, where am i going wrong?
 
Thanks in advance.
himansu
GeneralThread-safe MessageBox in OnMailSent event handlermemberMichael Freidgeim3 Jul '06 - 17:12 
In .Net 2.0 I had to change OnMailSent event handler to make it thread-safe.
See my blog post
Thread-safe MessageBox in Windows form [^]
 
Michael Freidgeim.
Blog: http://geekswithblogs.net/mnf/
GeneralStatics in SmtpAttachment classmemberTiTi____20 Apr '06 - 0:43 
Hi,
 
What's the reason for making the "inlineCount" and "attachCount" members static in the SmtpAttachment class? I don't see any good reason to use statics for this ... TBH it looks plain ugly.
 
The only thing that is done is incrementing those, and they're never reset. Then what is the use of these variables anyway? This looks like a bug to me, without even having used the library.
 
Greetings
GeneralRe: Statics in SmtpAttachment classmemberTiTi____21 Apr '06 - 0:27 
Confirmed, is a bug after testing. The whole project reeks of lack of quality, makes me wonder why this is still rated at 4.3... I rated 3 and that's before spotting this obvious error. Should've given it 2, tops Dead | X| ...
 
Anyway, easily solved by making onlineCount & attachCount members of SmtpEmailer class (not static, of course DUH) and incrementing/decrementing on adding/removing attachments. While you're at it, remove the n00b AttachmentList & AddressList classes, they serve absolutely no purpose other than obfuscating things D'Oh! | :doh: .

GeneralHelp ..im about to be crazy..membercoolshad15 Mar '06 - 15:37 
it's great dll..but
I see this exception..
{
Exception Details: System.Net.Sockets.SocketException: The requested name is valid and was found in the database, but it does not have the correct associated data being resolved for} Smile | :)
please any one send me the code to work with this dll and a name of a domain already has free POP..plz..all the working-already code.Smile | :) >.with the domain name and format of strings..?
for example i have a mail in "Gmail" domain.
what can i do to send from it?
 
thanks very muchSmile | :)
 

 

 

Generalgreat!memberMP3Observer14 Mar '06 - 12:09 
5 stars from me Smile | :)
GeneralError with attachments.membery2k4life4 Feb '06 - 18:17 

try
{
cs = new CryptoStream(new FileStream(attachment.FileName,
FileMode.Open,FileAccess.Read, FileShare.Read),
new ToBase64Transform(), CryptoStreamMode.Read);
}
catch(Exception ex)
{
buf.Append("--- Error with attachment: ");
buf.Append(attachment.FileName);
buf.Append(" ---");
buf.Append("\r\n");
buf.Append(ex.Message);
buf.Append("\r\n");
con.SendCommand(buf.ToString());
return;
}

 
I did not want an automated support email to not be sent if the attachment was not around.
General"Sent:" date wrong in Outlookmembermichaelloveusa31 Jan '06 - 8:26 
Whenever I send a message, the sent time in Outlook comes in as 5:00PM from the previous day not matter when I send it. Any ideas on how to address this?
 
Mon 1/30/2006 5:00 PM
Generalabout the encoding of attachmentsmemberBouarf3 Jan '06 - 23:20 
hello,
line length has some importance in attachment encoding
 
SMTPEMailer line 560 should be modified as follow:
 
// old code
num = cs.Read(fbuf, 0, 2048);
while(num > 0)
{                        
     con.SendData(Encoding.ASCII.GetChars(fbuf, 0, num), 0, num);
     num = cs.Read(fbuf, 0, 2048);
}
cs.Close();
 
// new code
 
int lineLength = 76;
char[] CRLF = {(Char)13 , (Char)10};
num = cs.Read(fbuf, 0, lineLength);
while(num > 0)
{         
     con.SendData(Encoding.ASCII.GetChars(fbuf, 0, num), 0, num);
     con.SendData(CRLF, 0, 2);
     num = cs.Read(fbuf, 0, lineLength);
}
cs.Close();
 
you can also modify the buffer size to 76 on line 530
 
this limits the line length to 76 chars and the attachment goes through ok
 
Patrick B.

Questionhow to send images with in the body of mailmembersreesiri8 Dec '05 - 1:13 
hi all,
 
how to send images with in the body of mail ..
not as attachment..
can any body help...
 
byeeeeeeeeeeeeee
sree
Generaldateformat not rfcmemberKylixs10 Oct '05 - 13:48 
hello,
its better to set the dateformat in rfc format:
Tue, 11 Oct 2005 01:47:12 +0200
 
this worked for me:
 
//set headers
con.SendCommand("DATA");
con.SendCommand("X-Mailer: smw.smtp.SmtpEmailer");
DateTime today = DateTime.Now;
buf.Append("DATE: ");
buf.Append(today.ToString("r").Replace("GMT","+0200"));
GeneralRe: dateformat not rfcmemberStar936 Jan '06 - 8:17 
...better:
 
buf.Append(today.ToString("r").Replace("GMT",today.ToString("zz00")));
 
Greetings!
Sebastian.
GeneralSmtpClient in .NET 2.0memberAlexander Kojevnikov14 Sep '05 - 22:25 
I suggest everyone to check out System.Net.Mail.SmtpClient[^] class in .NET 2.0. It's got all features of the class in this article but lacks its RFC incompatibilities.
 
HTH
 
Alexander Kojevnikov
MCSD.NET
Sydney, Australia

GeneralMail subject whithout correct iso-8859-1 ponctuationmemberandre.lourenco@link.pt12 Sep '05 - 0:37 
When we put some iso-8859-1 ponctuation like áéíóú the subject arrives at the destiny like ?????
AnswerRe: Mail subject whithout correct iso-8859-1 ponctuationmembergabrielbur14 Nov '07 - 4:17 
In SmtpConnection Class I replaced the ASCII encoding by ANSI (the default). It worked for me.
 
//OLD CODE//
 
internal void Open(string host, int port)
{
try
{
if (host == null || host.Trim().Length == 0 || port <= 0)
{
throw new System.ArgumentException("Invalid Argument found.");
}
socket.Connect(host, port);
reader = new StreamReader(socket.GetStream(), System.Text.Encoding.ASCII);
writer = new StreamWriter(socket.GetStream(), System.Text.Encoding.ASCII);
connected = true;
}
catch (Exception ex)
{
throw ex;
}
}
 

//NEW CODE//
 
internal void Open(string host, int port)
{
try
{
if (host == null || host.Trim().Length == 0 || port <= 0)
{
throw new System.ArgumentException("Invalid Argument found.");
}
socket.Connect(host, port);
reader = new StreamReader(socket.GetStream(), System.Text.Encoding.Default);
writer = new StreamWriter(socket.GetStream(), System.Text.Encoding.Default);
connected = true;
}
catch (Exception ex)
{
throw ex;
}
}
GeneralLittle bug with big effectmemberStar936 Jul '05 - 23:04 
Hi @ all!
 
In the past some emails I sended came back with the error "Syntax error in address headers". After searching a long time (!) I found the cause.
The email addesses you are sending to are comma-seperated: <1a.b@c.de>,<2a.b@c.de>,<3a.b@c.de> - check out http://cr.yp.to/immhf/recip.html[^] .
 
That's why I replaced the existing semicolon with comma:
 
buf.Append("To: ");
buf.Append(to[0]);
for(int x = 1; x < to.Count; ++x)
{
buf.Append(",");
buf.Append(to[x]);
}
con.SendCommand(buf.ToString());
if(cc.Count > 0)
{
buf.Length = 0;
buf.Append("Cc: ");
buf.Append(cc[0]);
for(int x = 1; x < cc.Count; ++x)
{
buf.Append(",");
buf.Append(cc[x]);
}
con.SendCommand(buf.ToString());
}
 
if(bcc.Count > 0)
{
buf.Length = 0;
buf.Append("Bcc: ");
buf.Append(bcc[0]);
for(int x = 1; x < bcc.Count; ++x)
{
buf.Append(",");
buf.Append(bcc[x]);
}
con.SendCommand(buf.ToString());
}
 
Greetings!
Sebastian.
QuestionCan you see the image in your mail?susshandlim26 Apr '05 - 0:17 
I send mail with image file by 'As inline HTML Image'.
I thought it means the image shows in mail not attachment.
But, I can't see the image in it.
 
I received the mail without image file.
 
Do I have to do setting for this program?
 
Anyway, Thank you,,,
 
this program is very good...
AnswerRe: Can you see the image in your mail?memberThe_Mega_ZZTer27 Sep '05 - 7:05 
You need to send the e-mail as HTML and place an img tag inside that points to the image.
 
<img src="cid:MY_FILENAME_WITHOUT_EXTENSION">
GeneralRe: Can you see the image in your mail?membersanish197914 Sep '07 - 0:34 
<img src="cid:MY_FILENAME_WITHOUT_EXTENSION">
 
i put my my image but still the image cant see can you give an example with an image name
 
my image attached is DIC101.JPG how should i give it in my html mail
 
i had given like this
 
<img src="cid:DIC101">
 
but image is not not displayed with the html
 
please help
 
Sanish
GeneralBCC in Headermemberstilton@cheese.com13 Apr '05 - 3:03 
I noticed you can view the BCC email addresses in the email header.
 
when I remove the following code in SmtpEmail.cs it is gone, but I can still receive bcc mails
 
if(bcc.Count > 0)
       {
       buf.Length = 0;
       buf.Append("BCC: ");
       buf.Append(bcc[0]);
       for(int x = 1; x < bcc.Count; ++x)
       {
       buf.Append(";");
       buf.Append(bcc[x]);				
       }
       con.SendCommand(buf.ToString());
       }
 

GeneralNice but Spam filters let the Emails not passmemberStar935 Apr '05 - 14:26 
Hi!
 
I tested the library in different ways. It seems to be very safe. But after turning on a Spam filter at my Email account I saw that the Emails not passed anymore. I fixed (till now) 3 scored points of search, which takes Emails to Spam Mails:
 
1. NO_REAL_NAME:
------------------------
The filter looks for Name and Email address in the 'From:'-line. The library do not support this. To fix this, you should declare another property say 'FromName' in the SmtpEmailer.cs and extend (go to the point where you build the headers) 'buf.Append("FROM: ");buf.Append(from);'. You get something like this: 'buf.Append("FROM: " + from_name + "<");buf.Append(from + ">");'. This solves the first not high scored Spam filter search point.
 
2. INVALID_DATE:
------------------------
This one applies to all who use other system languages than (US) English, e.g. myself. My system setting is German. The library build a header for date: 'DateTime today = DateTime.Now;buf.Append("DATE: ");buf.Append(today.ToLongDateString());'. This affects in sending a No-Standard-Date. Standard would be 'Tue, 05 Apr 2005 22:26:58 (GMT)' or 'Tue, 05 Apr 2005 22:26:58 +0200'. I get at this point 'Dienstag, 5. April 2005'. I modified this as follows: 'DateTime today = DateTime.Now;string strToday = today.ToString("r");strToday=strToday.Replace(strToday.Substring(strToday.Length-3,3),"+0200");buf.Append("DATE: ");buf.Append(strToday);'. Now I get a standard date format for this Email header.
 
3. RATWARE_HASH_2_V2
------------------------
This is a very high scored search point and belongs to the header 'X-Mailer'. I would not swear to that, but I think the spam filter software goes through a list with known Email software names and if the name you specify at 'con.SendCommand("X-Mailer: smw.smtp.SmtpEmailer");' do not match this list... I don't know another solution but: '//con.SendCommand("X-Mailer: smw.smtp.SmtpEmailer");'. (This header is optional).
 
MIME_BASE_64_BLANKS (Extra blank lines in base64 encoding): High scored, No solution.
BAYES_00 (Bayesian spam probability is 0 to 1%): No solution.
 

Every comments are welcome!
Sebastian.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 1 Mar 2003
Article Copyright 2002 by Steaven Woyan
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid