using System;
using System.Text;
using HB.Web;
namespace HB.Web.Mail
{
/// <summary>
/// Sends <see cref="IMailMessage"/> objects to a SMTP server.
/// </summary>
public class Smtp
{
/// <summary>
/// Sends an e-mail message using arguments supplied in the
/// properties of the IMailMessage object.
/// </summary>
/// <param name="server">The ip of the SMTP mail server to use to send all e-mail messages.</param>
/// <param name="username">The username of the account on the SMTP server.</param>
/// <param name="password">The password of the account on the SMTP server.</param>
/// <param name="message">The IMailMessage to send.</param>
/// <exception cref="ApplicationException">When an unexpected reply code is received.</exception>
/// <exception cref="ApplicationException">When an error occured while sending the email.</exception>
/// <exception cref="ArgumentNullException">When paramater server, message, username or password is null.</exception>
public static void Send(string server, IMailMessage message, string username, string password)
{
if(server == null)
throw new ArgumentNullException("server");
if(message == null)
throw new ArgumentNullException("message");
if(username == null)
throw new ArgumentNullException("username");
if(password == null)
throw new ArgumentNullException("password");
ArpaClientStream connection = null;
try
{
connection = ArpaClientStream.CreateConnection(server, 25);
}
catch(Exception e)
{
throw new ApplicationException("A connection to the SMTP server could not be made.", e);
}
ArpaReply reply;
try
{
reply = connection.ReadAll();
if(reply.ReplyCode != 220)
throw new InvalidReplyCodeException(220, reply);
//connect
connection.Write("EHLO " + System.Environment.MachineName);
reply = connection.ReadAll();
if(reply.ReplyCode != 250)
throw new InvalidReplyCodeException(250, reply);
//request login
connection.Write("AUTH LOGIN");
reply = connection.ReadAll();
if(reply.ReplyCode != 334)
throw new InvalidReplyCodeException(334, reply);
//send username
byte[] loginInfo = Encoding.ASCII.GetBytes(username);
connection.Write(Convert.ToBase64String(loginInfo));
reply = connection.ReadAll();
if(reply.ReplyCode != 334)
throw new InvalidReplyCodeException(334, reply);
//send password
loginInfo = Encoding.ASCII.GetBytes(password);
connection.Write(Convert.ToBase64String(loginInfo));
reply = connection.ReadAll();
if(reply.ReplyCode != 235)
throw new InvalidReplyCodeException(235, reply);
SendData(connection, message);
}
catch(Exception e)
{
throw new ApplicationException("An error occurred while communicating with the SMTP server.", e);
}
finally
{
connection.Close();
}
}
/// <summary>
/// Sends an e-mail message using arguments supplied in the
/// properties of the IMailMessage object.
/// </summary>
/// <param name="server">The ip of the SMTP mail server to use to send all e-mail messages.</param>
/// <param name="message">The IMailMessage to send.</param>
/// <remarks>The HELO command is used to greet the server.</remarks>
/// <exception cref="ApplicationException">When an unexpected reply code is received.</exception>
/// <exception cref="ApplicationException">When an error occured while sending the email.</exception>
/// <exception cref="ArgumentNullException">When parameter server or message is null.</exception>
public static void Send(string server, IMailMessage message)
{
if(server == null)
throw new ArgumentNullException("server");
if(message == null)
throw new ArgumentNullException("message");
using(ArpaClientStream connection = ArpaClientStream.CreateConnection(server, 25))
{
try
{
ArpaReply reply = connection.ReadAll();
if(reply.ReplyCode != 220)
throw new InvalidReplyCodeException(220, reply);
//connect
connection.Write("HELO " + Environment.MachineName);
reply = connection.ReadAll();
if(reply.ReplyCode != 250)
throw new InvalidReplyCodeException(250, reply);
SendData(connection, message);
}
catch(Exception e)
{
throw new ApplicationException("An error occurred while sending the e-mail DATA to the SMTP server.", e);
}
}
}
/// <summary>
/// Sends the DATA portion of an e-mail to a STMP server.
/// </summary>
/// <param name="connection">The connection to use to send the e-mail.</param>
/// <param name="message">The e-mail to send.</param>
/// <exception cref="ApplicationException">When an error occured while sending the email.</exception>
/// <exception cref="ApplicationException">When an unexpected reply code is received.</exception>
private static void SendData(ArpaClientStream connection, IMailMessage message)
{
//MAIL FROM
if(message.From == null)
throw new ArgumentException("From property cannot be null.", "message.From");
connection.Write("MAIL FROM:<" + message.From.Address + ">");
ArpaReply reply = connection.ReadAll();
if(reply.ReplyCode != 250)
throw new InvalidReplyCodeException(250, reply);
//RCPT TO - TO
foreach(IMailAddress address in message.To)
{
connection.Write("RCPT TO:<" + address.Address + ">");
reply = connection.ReadAll();
if(reply.ReplyCode != 250)
throw new InvalidReplyCodeException(250, reply);
}
//RCPT TO - CC
foreach(IMailAddress address in message.Cc)
{
connection.Write("RCPT TO:<" + address.Address + ">");
reply = connection.ReadAll();
if(reply.ReplyCode != 250)
throw new InvalidReplyCodeException(250, reply);
}
//RCPT TO - BCC
foreach(IMailAddress address in message.Bcc)
{
connection.Write("RCPT TO:<" + address.Address + ">");
reply = connection.ReadAll();
if(reply.ReplyCode != 250)
throw new InvalidReplyCodeException(250, reply);
}
//send DATA
connection.Write("DATA");
reply = connection.ReadAll();
if(reply.ReplyCode != 354)
throw new InvalidReplyCodeException(354, reply);
message.ToData(connection);
//end send DATA
connection.Write(ArpaClientStream.CRLF + ".");
reply = connection.ReadAll();
if(reply.ReplyCode != 250)
throw new InvalidReplyCodeException(250, reply);
}
}
}