| Recently one of our readers
and I went back and forth via email about putting together a little app
that he wanted his mother to be able to use that would retrieve her current
IP address and email it to him, so that he could remote to her desktop
to help her out with whatever computer problem she may have been having.
One of the problems we had was either finding or writing code that would
enable the app to send this email without relying on
her having the SMTP service present and running on her machine, and without
relying on the presence of CDO either. The .NET System.Web.Mail.SmtpMail
class uses Collaboration Data Objects for Windows 2000 (CDOSYS) message
component under the hood, so if Mom is running Windows ME, for example,
you are plum out of luck with your app. Since then, we've had several
additional requests for this type of code, so I thought it would be worthwhile
to investigate this further.
Sending email via TCP using the native SMTP RFC commands "HELO",
"MAIL From", RCPT TO", etc. is no big deal. That's one
of the first tricks we learn with Telnet. Finding or writing managed code
that will do so reliably is another story. The code in the class that
follows is not my original code - I've cobbled it together from three
different sample sources, fixing namespaces, error handling, and other
minor items, changing console code to class library code, and providing
a complete Winforms - based test harness front end that illustrates its
correct usage. I've also included sample code to correctly process and
add a mail attachment via an OpenFileDialog here. This code MIME encodes
and transmits the attachment(s) according to the specification.
Since the class code speaks for itself, I'll simply post it below. It
should be pretty much self-explanatory. You can download the complete
solution at the link below and you should be able to plug this class into
your applications with no changes necessary - right out of the box.
using
System;
using System.Text;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Web.Mail;
namespace SMTP
{
/// <summary>
/// provides methods to send email via smtp direct to mail server
/// </summary>
public class SmtpDirect
{
/// <summary>
/// Get / Set the name of the SMTP mail server
/// </summary>
public static string SmtpServer;
private enum SMTPResponse: int
{
CONNECT_SUCCESS = 220,
GENERIC_SUCCESS = 250,
DATA_SUCCESS = 354,
QUIT_SUCCESS = 221
}
public static bool Send(MailMessage message)
{
IPHostEntry IPhst = Dns.Resolve(SmtpServer);
IPEndPoint endPt = new IPEndPoint(IPhst.AddressList[0], 25);
Socket s= new Socket(endPt.AddressFamily, SocketType.Stream,ProtocolType.Tcp);
s.Connect(endPt);
if(!Check_Response(s, SMTPResponse.CONNECT_SUCCESS))
{
s.Close();
return false;
}
Senddata(s, string.Format("HELO {0}\r\n", Dns.GetHostName()
));
if(!Check_Response(s, SMTPResponse.GENERIC_SUCCESS))
{
s.Close();
return false;
}
Senddata(s, string.Format("MAIL From: {0}\r\n", message.From
));
if(!Check_Response(s, SMTPResponse.GENERIC_SUCCESS))
{
s.Close();
return false;
}
string _To = message.To;
string[] Tos= _To.Split(new char[] {';'});
foreach (string To in Tos)
{
Senddata(s, string.Format("RCPT TO: {0}\r\n", To));
if(!Check_Response(s, SMTPResponse.GENERIC_SUCCESS))
{
s.Close();
return false;
}
}
if(message.Cc!=null)
{
Tos= message.Cc.Split(new char[] {';'});
foreach (string To in Tos)
{
Senddata(s, string.Format("RCPT TO: {0}\r\n", To));
if(!Check_Response(s, SMTPResponse.GENERIC_SUCCESS))
{
s.Close();
return false;
}
}
}
StringBuilder Header=new StringBuilder();
Header.Append("From: " + message.From + "\r\n");
Tos= message.To.Split(new char[] {';'});
Header.Append("To: ");
for( int i=0; i< Tos.Length; i++)
{
Header.Append( i > 0 ? "," : "" );
Header.Append(Tos[i]);
}
Header.Append("\r\n");
if(message.Cc!=null)
{
Tos= message.Cc.Split(new char[] {';'});
Header.Append("Cc: ");
for( int i=0; i< Tos.Length; i++)
{
Header.Append( i > 0 ? "," : "" );
Header.Append(Tos[i]);
}
Header.Append("\r\n");
}
Header.Append( "Date: " );
Header.Append(DateTime.Now.ToString("ddd, d M y H:m:s z"
));
Header.Append("\r\n");
Header.Append("Subject: " + message.Subject+ "\r\n");
Header.Append( "X-Mailer: SMTPDirect v1\r\n" );
string MsgBody = message.Body;
if(!MsgBody.EndsWith("\r\n"))
MsgBody+="\r\n";
if(message.Attachments.Count>0)
{
Header.Append( "MIME-Version: 1.0\r\n" );
Header.Append( "Content-Type: multipart/mixed; boundary=unique-boundary-1\r\n"
);
Header.Append("\r\n");
Header.Append( "This is a multi-part message in MIME format.\r\n"
);
StringBuilder sb = new StringBuilder();
sb.Append("--unique-boundary-1\r\n");
sb.Append("Content-Type: text/plain\r\n");
sb.Append("Content-Transfer-Encoding: 7Bit\r\n");
sb.Append("\r\n");
sb.Append(MsgBody + "\r\n");
sb.Append("\r\n");
foreach(object o in message.Attachments)
{
MailAttachment a = o as MailAttachment;
byte[] binaryData;
if(a!=null)
{
FileInfo f = new FileInfo(a.Filename);
sb.Append("--unique-boundary-1\r\n");
sb.Append("Content-Type: application/octet-stream; file="
+ f.Name + "\r\n");
sb.Append("Content-Transfer-Encoding: base64\r\n");
sb.Append("Content-Disposition: attachment; filename=" +
f.Name + "\r\n");
sb.Append("\r\n");
FileStream fs = f.OpenRead();
binaryData = new Byte[fs.Length];
long bytesRead = fs.Read(binaryData, 0, (int)fs.Length);
fs.Close();
string base64String = System.Convert.ToBase64String(binaryData, 0,binaryData.Length);
for(int i=0; i< base64String.Length ; )
{
int nextchunk=100;
if(base64String.Length - (i + nextchunk ) <0)
nextchunk = base64String.Length -i;
sb.Append(base64String.Substring(i, nextchunk));
sb.Append("\r\n");
i+=nextchunk;
}
sb.Append("\r\n");
}
}
MsgBody=sb.ToString();
}
Senddata(s, ("DATA\r\n"));
if(!Check_Response(s, SMTPResponse.DATA_SUCCESS))
{
s.Close();
return false;
}
Header.Append( "\r\n" );
Header.Append( MsgBody );
Header.Append( ".\r\n" );
Header.Append( "\r\n" );
Header.Append( "\r\n" );
Senddata(s, Header.ToString());
if(!Check_Response(s, SMTPResponse.GENERIC_SUCCESS ))
{
s.Close();
return false;
}
Senddata(s, "QUIT\r\n");
Check_Response(s, SMTPResponse.QUIT_SUCCESS );
s.Close();
return true;
}
private static void Senddata(Socket s, string msg)
{
byte[] _msg = Encoding.ASCII.GetBytes(msg);
s.Send(_msg , 0, _msg .Length, SocketFlags.None);
}
private static bool Check_Response(Socket s, SMTPResponse response_expected
)
{
string sResponse;
int response;
byte[] bytes = new byte[1024];
while (s.Available==0)
{
System.Threading.Thread.Sleep(100);
}
s.Receive(bytes, 0, s.Available, SocketFlags.None);
sResponse = Encoding.ASCII.GetString(bytes);
response = Convert.ToInt32(sResponse.Substring(0,3));
if(response != (int)response_expected)
return false;
return true;
}
}
}
|
Download
the code that accompanies this article
| | Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform. |
|