using System;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Net.Mail;
using System.Net;
using System.Security;
namespace Westwind.InternetTools
{
/// <summary>
/// SMTP Wrapper around System.Net.Email.SmtpClient. Provided
/// here mainly to provide compatibility with existing wwSmtp code
/// and to provide a slightly more user friendly front end interface
/// on a single object.
/// </summary>
public class wwSmtpNative
{
/// <summary>
/// Mail Server to send message through. Should be a domain name
/// (mail.yourserver.net) or IP Address (211.123.123.123).
///
/// You can also provide a port number as part of the string which will
/// override the ServerPort (yourserver.net:211)
/// <seealso>Class wwSmtp</seealso>
/// </summary>
public string MailServer = "";
/// <summary>
/// Port on the mail server to send through. Defaults to port 25.
/// </summary>
public int ServerPort = 25;
/// <summary>
/// Email address or addresses of the Recipient. Comma delimit multiple addresses. To have formatted names use
/// "Rick Strahl" <rstrahl@west-wind.com>
/// </summary>
public string Recipient = "";
/// <summary>
/// Carbon Copy Recipients
/// </summary>
public string CC = "";
/// <summary>
/// Blind Copy Recipients
/// </summary>
public string BCC = "";
/// <summary>
/// Email address of the sender
/// </summary>
public string SenderEmail = "";
/// <summary>
/// Display name of the sender (optional)
/// </summary>
public string SenderName = "";
/// <summary>
/// The ReplyTo address
/// </summary>
public string ReplyTo = "";
/// <summary>
/// Message Subject.
/// </summary>
public string Subject = "";
/// <summary>
/// The body of the message.
/// </summary>
public string Message = "";
/// <summary>
/// Username to connect to the mail server.
/// </summary>
public string Username = "";
/// <summary>
/// Password to connect to the mail server.
/// </summary>
public string Password = "";
/// <summary>
/// The content type of the message. text/plain default or you can set to any other type like text/html
/// </summary>
public string ContentType = "text/plain";
/// <summary>
/// Character Encoding for the message.
/// </summary>
public string CharacterEncoding = "8bit";
/// <summary>
/// The character Encoding used to write the stream out to disk
/// Defaults to the default Locale used on the server.
/// </summary>
public System.Text.Encoding Encoding = Encoding.Default;
/// <summary>
/// Determines the priority of the message
/// </summary>
public MailPriority Priority = MailPriority.Normal;
/// <summary>
/// An optional file name that appends logging information for the TCP/IP messaging
/// to the specified file.
/// </summary>
public string LogFile = "";
/// <summary>
/// Determines whether wwSMTP passes back errors as exceptions or
/// whether it sets error properties. Right now only error properties
/// work reliably.
/// </summary>
public bool HandleExceptions = true;
/// <summary>
/// An Error Message if the result is negative or Error is set to true;
/// </summary>
public string ErrorMessage = "";
/// <summary>
/// Error Flag set when an error occurs.
/// </summary>
public bool Error = false;
/// <summary>
/// Connection timeouts for the mail server in seconds. If this timeout is exceeded waiting for a connection
/// or for receiving or sending data the request is aborted and fails.
/// </summary>
public int Timeout = 30;
/// <summary>
/// Event fired when sending of a message or multiple messages
/// is complete and the connection is to be closed. This event
/// occurs only once per connection as opposed to the MessageSendComplete
/// event which fires after each message is sent regardless of the
/// number of SendMessage operations.
/// </summary>
public event delSmtpNativeEvent SendComplete;
/// <summary>
/// Event that's fired after each message is sent. This
/// event differs from SendComplete that it fires
/// after each send operation of each message rather
/// than before closing the connection.
/// </summary>
public event delSmtpNativeEvent MessageSendComplete;
/// <summary>
/// Event fired when an error occurs during processing and before
/// the connection is closed down.
/// </summary>
public event delSmtpNativeEvent SendError;
/// <summary>
/// Connects to the mail server.
/// </summary>
/// <returns>True or False</returns>
public bool Connect()
{
return true;
}
/// <summary>
/// Fully self contained mail sending method. Sends an email message by connecting
/// and disconnecting from the email server.
/// </summary>
/// <returns>true or false</returns>
public bool SendMail()
{
//if (!string.IsNullOrEmpty(this.LogFile))
// this.LogString("\r\n*** Starting SMTP connection - " + DateTime.Now.ToString());
// *** Allow for server:Port syntax (west-wind.com:1212)
int serverPort = this.ServerPort;
string server = this.MailServer;
// *** if there's a port we need to split the address
string[] parts = server.Split(':');
if (parts.Length > 1)
{
server = parts[0];
serverPort = int.Parse(parts[1]);
}
if (server == null || server == "")
{
this.SetError("No Mail Server specified.");
return false;
}
SmtpClient smtp = null;
try
{
smtp = new SmtpClient(server, serverPort);
}
catch (SecurityException ex)
{
this.SetError("Unable to create SmptClient due to missing permissions. If you are using a port other than 25 for your email server, SmtpPermission has to be explicitly added in Medium Trust.");
return false;
}
// *** This is a Total Send Timeout not a Connection timeout!
smtp.Timeout = this.Timeout * 1000;
if (!string.IsNullOrEmpty(this.Username))
smtp.Credentials = new NetworkCredential(this.Username, this.Password);
// *** Create and configure the message
MailMessage msg = this.GetMessage();
try
{
smtp.Send(msg);
}
catch (Exception ex)
{
this.SetError(ex.Message);
if (this.SendError != null)
this.SendError(this);
return false;
}
if (this.SendComplete != null)
this.SendComplete(this);
return true;
}
/// <summary>
/// Configures the message interface
/// </summary>
/// <param name="msg"></param>
protected virtual MailMessage GetMessage()
{
MailMessage msg = new MailMessage();
msg.Body = this.Message;
msg.Subject = this.Subject;
msg.From = new MailAddress(this.SenderEmail, this.SenderName);
if (!string.IsNullOrEmpty(this.ReplyTo))
msg.ReplyTo = new MailAddress(this.ReplyTo);
// *** Send all the different recipients
this.SendRecipients(msg.To, this.Recipient);
this.SendRecipients(msg.CC, this.CC);
this.SendRecipients(msg.Bcc, this.BCC);
//using (MemoryStream ms = new MemoryStream())
//{
// ms.Write(this.Encoding.GetBytes(this.Message));
// ms.Position = 0L;
// AlternateView vw = new AlternateView(ms);
// vw.ContentType = "text/html";
// vw.TransferEncoding = System.Net.Mime.TransferEncoding.Base64;
// msg.AlternateViews.Add(vw);
//}
//msg.Headers.Add("x-mailer", "wwSmtp .Net");
if (this.ContentType.StartsWith("text/html"))
msg.IsBodyHtml = true;
else
msg.IsBodyHtml = false;
//msg.Headers.Add("Content-Type",this.ContentType);
//msg.Headers.Add("Content-Transfer-Encoding", this.CharacterEncoding);
msg.Priority = this.Priority;
msg.BodyEncoding = this.Encoding;
return msg;
}
/// <summary>
/// Sends all recipients from a comma or semicolon separated list.
/// </summary>
/// <param name="recipients"></param>
/// <returns></returns>
void SendRecipients(MailAddressCollection address, string recipients)
{
if (recipients == null || recipients.Length == 0)
return;
string[] recips = recipients.Split(',', ';');
for (int x = 0; x < recips.Length; x++)
{
address.Add(new MailAddress(recips[x]));
}
}
/// <summary>
/// Strips out just the email address from a full email address that might contain a display name
/// in the format of: "West Wind Web Monitor" <rstrahl@west-wind.com>
/// </summary>
/// <param name="lcFullEmail">Full email address to parse. Note currently only "<" and ">" tags are recognized as message delimiters</param>
/// <returns>only the email address</returns>
string GetEmailFromFullAddress(string fullEmail)
{
if (fullEmail.IndexOf("<") > 0)
{
int lnIndex = fullEmail.IndexOf("<");
int lnIndex2 = fullEmail.IndexOf(">");
string lcEmail = fullEmail.Substring(lnIndex + 1, lnIndex2 - lnIndex - 1);
return lcEmail;
}
return fullEmail;
}
/// <summary>
/// Provided for compatibility with wwSmtp to provide Async send operation.
/// </summary>
/// <returns></returns>
public void SendMailAsync()
{
ThreadStart delSendMail = new ThreadStart(this.SendMailRun);
delSendMail.BeginInvoke(null, null);
// Thread mailThread = new Thread(delSendMail);
// mailThread.Start();
}
protected void SendMailRun()
{
// Create an extra reference to insure GC doesn't collect
// the reference from the caller
wwSmtpNative Email = this;
Email.SendMail();
}
/// <summary>
/// Logs a message to the specified LogFile
/// </summary>
/// <param name="FormatString"></param>
/// <param name="?"></param>
protected void LogString(string message)
{
if (string.IsNullOrEmpty(this.LogFile))
return;
if (!message.EndsWith("\r\n"))
message += "\r\n";
using (StreamWriter sw = new StreamWriter(this.LogFile, true))
{
sw.Write(message);
}
}
/// <summary>
/// Internally used to set errors
/// </summary>
/// <param name="errorMessage"></param>
private void SetError(string errorMessage)
{
if (errorMessage == null || errorMessage.Length == 0)
{
this.ErrorMessage = "";
this.Error = false;
return;
}
ErrorMessage = errorMessage;
Error = true;
}
}
public delegate void delSmtpNativeEvent(wwSmtpNative Smtp);
}