📄 dnsmail.cs
字号:
// $Id: DnsMail.cs,v 1.17 2006/08/15 13:07:00 ethem Exp $
namespace Erle.DnsMail
{
using System;
using System.Collections;
using System.Text.RegularExpressions;
using IPAddress = System.Net.IPAddress;
using IPEndPoint = System.Net.IPEndPoint;
using StringBuilder = System.Text.StringBuilder;
using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
public class DnsMail : IDisposable, ISendableOneByOne
{
private SmtpClient m_Client;
#region Constants
private const int MaxBuffer = 8192;
private const int TimeOut = 3000000;
private const int MaxLength = 512 * 1024;
private static readonly byte[] crlf_dot_crlf = System.Text.Encoding.ASCII.GetBytes("\r\n" + "." + "\r\n");
public static readonly string EmailRegexString = @"^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
private static readonly Regex EmailRegex = new Regex(EmailRegexString, RegexOptions.IgnoreCase | RegexOptions.Compiled);
#endregion
#region Constructors
public DnsMail() { }
public DnsMail(MailInfo info)
{
MailInfo = info;
}
~DnsMail()
{
Dispose(false);
}
#endregion
#region Properties
private MailInfo mi;
public MailInfo MailInfo
{
get
{
if (mi == null)
mi = new MailInfo();
return mi;
}
set
{
if (value == null)
throw new ArgumentNullException("MailInfo");
mi = value;
}
}
private int smtpport = 25;
public int Port
{
get
{
return smtpport;
}
set
{
if (value < 0x0000 || value > 0xFFFF)
throw new ArgumentOutOfRangeException("Port");
smtpport = value;
}
}
private string helo;
public string HeloDomain
{
get
{
return (helo == null || helo == string.Empty) ? DNSAPI.HelloHost : helo;
}
set
{
helo = value;
}
}
private bool uselog;
public bool UseLog
{
get
{
return uselog;
}
set
{
uselog = value;
}
}
int tickcount = -1;
public int TickCount
{
get
{
return tickcount;
}
}
private IPEndPoint localpoint;
public IPEndPoint LocalPoint
{
get
{
if (localpoint == null)
localpoint = new IPEndPoint(IPAddress.Any, 0);
return localpoint;
}
set
{
localpoint = value;
}
}
public int LastCode
{
get
{
if (m_Client != null)
return m_Client.LastCode;
return 0;
}
}
public string LastAnswer
{
get
{
if (m_Client != null)
return m_Client.LastAnswer;
return String.Empty;
}
}
public string LastResponse
{
get
{
if (m_Client != null)
return m_Client.LastResponse;
return String.Empty;
}
}
private bool usessl;
public bool UseSsl
{
get { return usessl; }
set { usessl = value; }
}
public bool SslActive
{
get
{
return (m_Client != null && m_Client.SslActive);
}
}
public X509Certificate X509Certificate
{
get
{
if (m_Client != null)
return m_Client.X509Certificate;
return null;
}
}
#endregion
#region Events
public event HostResolvedHandler HostResolved;
public event ConnectedHandler Connected;
public event EventHandler Authenticated;
public event RecipientsAddedHandler RecipientsAdded;
public event ReadyToSendMassMailHandler ReadyToSendMassMail;
public event ProgressHandler SendProgress;
public event EventHandler Sent;
public event ClosedHandler Closed;
#endregion
#region Protected Methods
protected virtual void OnHostResolved(String host, ICollection IPs)
{
if (this.HostResolved != null)
HostResolved(host, IPs);
}
protected virtual void OnConnect(String connectedIP)
{
if (this.Connected != null)
Connected(connectedIP);
}
protected virtual void OnAuthenticated(EventArgs e)
{
if (this.Authenticated != null)
Authenticated(this, e);
}
protected virtual void OnRecipientsAdded(RecipientCollection recipients)
{
if (this.RecipientsAdded != null)
RecipientsAdded(recipients);
}
protected virtual void OnReadyToSendMassMail(EventArgs e)
{
if (this.ReadyToSendMassMail != null)
ReadyToSendMassMail(MailInfo);
}
protected virtual void OnSendProgress(int bytesSent, int bytesRemaining)
{
if (this.SendProgress != null)
SendProgress(bytesSent, bytesRemaining);
}
protected virtual void OnSent(EventArgs e)
{
if (this.Sent != null)
Sent(this, e);
}
protected virtual void OnClosed(EventArgs e)
{
if (this.Closed != null)
Closed(UseLog ? m_Client.logs.ToString() : String.Empty);
}
bool datasent = false, disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
disposed = true;
if (m_Client != null)
{
try
{
m_Client.Close();
}
catch { }
try
{
OnClosed(EventArgs.Empty);
}
catch { }
finally
{
m_Client.UseLog = false;
}
m_Client = null;
}
}
}
#region ISendableOneByOne.BatchStatus
event SentByOneStatusHandler SentByOneStatus;
event SentByOneStatusHandler ISendableOneByOne.SentByOneStatus
{
add { SentByOneStatus += value; }
remove { SentByOneStatus -= value; }
}
protected virtual void OnSentByOneStatus(SentByOneStatusEventArgs e)
{
if (this.SentByOneStatus != null)
SentByOneStatus(e);
}
#endregion
#region IDisposable.Dispose
void System.IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#endregion
#region Public Functions
public static bool EmailCheck(String email)
{
return EmailRegex.IsMatch(email);
}
public static string FindEmailDomain(string email)
{
if (email != null && email != string.Empty && EmailCheck(email))
{
string[] _emarr = email.Split(new char[] { '@' }, 2);
return _emarr[1].ToLower();
}
return null;
}
public void Send()
{
if (datasent)
throw new InvalidOperationException("E-mail has already been sent.");
if (disposed)
throw new ObjectDisposedException(this.GetType().FullName);
try
{
initialize();
bool ignore;
int rcptcount = addrecipients();
senddata(((Recipient)mi.Recipients[0]).ToString(), true, rcptcount, out ignore);
}
finally
{
tickcount = Environment.TickCount - tickcount;
((IDisposable)this).Dispose();
}
}
#endregion
#region ISendOneByOne
void ISendableOneByOne.SendOneByOne(string formattedBody)
{
if (disposed)
throw new ObjectDisposedException(this.GetType().FullName);
try
{
initialize();
sendbatchsend(formattedBody);
}
finally
{
tickcount = Environment.TickCount - tickcount;
((IDisposable)this).Dispose();
}
}
private void sendbatchsend(string originalBody)
{
string originalSubject = mi.Subject;
bool readycontrol = false, senddatax = false, sendersent = true;
foreach (Recipient rec in mi.Recipients)
{
try
{
if (!sendersent)
{
sendersent = true;
if (!m_Client.MailFrom(mi.From))
throw new MailServerException(m_Client.LastResponse);
}
bool isok = m_Client.RcptTo(rec.Email);
if (!isok)
{
rec.valid = false;
rec.code = m_Client.LastCode;
rec.answer = m_Client.LastResponse;
SentByOneStatusEventArgs e = new SentByOneStatusEventArgs(rec, false);
OnSentByOneStatus(e);
continue;
}
if (!readycontrol)
{
readycontrol = true;
OnReadyToSendMassMail(EventArgs.Empty);
originalSubject = mi.Subject;
}
rec.valid = isok;
rec.code = m_Client.LastCode;
rec.answer = m_Client.LastResponse;
IRecipient ir = rec as IRecipient;
StringBuilder sb = new StringBuilder(originalBody);
string[] pars = ((IRecipient)rec).BodyParams;
if (pars != null && pars.Length > 0)
{
for (int i = 0; i < pars.Length; i++)
sb.Replace("{" + i + "}", pars[i]);
}
mi.Body = sb.ToString();
mi.Subject = (ir.Subject == null) ? originalSubject : ir.Subject;
senddata(rec.ToString(), false, 1, out senddatax);
if (senddatax)
sendersent = false;
SentByOneStatusEventArgs ex = new SentByOneStatusEventArgs(rec, mi.sent);
OnSentByOneStatus(ex);
}
catch
{
rec.valid = false;
rec.code = m_Client.LastCode;
rec.answer = m_Client.LastResponse;
SentByOneStatusEventArgs e = new SentByOneStatusEventArgs(rec, false);
OnSentByOneStatus(e);
}
}
mi.Body = originalBody;
mi.Subject = originalSubject;
}
#endregion
#region Private Functions
private void initialize()
{
if (mi == null)
throw new ArgumentNullException("MailInfo");
if (FindEmailDomain(mi.From) == null)
throw new EmailException("From must be defined.");
if (mi.Recipients == null || mi.Recipients.Count < 1)
throw new EmailException("Recipients must be defined.");
Boolean usedMx = (mi.Recipients.Domain != null && mi.Recipients.Domain != String.Empty);
String resDom = usedMx ? (mi.Recipients.Domain)
: (mi.MailServer != null && mi.MailServer != String.Empty)
? mi.MailServer
: DNSAPI.LocalHost;
MxRecord[] mxs;
IPAddress[] ips;
DnsCache.InternalResolve(ref resDom, ref usedMx, out mxs, out ips);
#region resolved
if (this.HostResolved != null)
{
if (usedMx)
{
String[] servers = new String[mxs.Length];
for (int i = 0; i < mxs.Length; i++)
servers[i] = ((MxRecord)mxs[i]).NameExchange;
OnHostResolved(resDom, servers);
}
else
{
String[] servers = new String[ips.Length];
for (int i = 0; i < ips.Length; i++)
servers[i] = ((IPAddress)ips[i]).ToString();
OnHostResolved(resDom, servers);
}
}
#endregion
tickcount = Environment.TickCount;
string smtpanswer = string.Empty;
if (usedMx)
{
foreach (MxRecord mx in mxs)
if (mx.IPAddresses != null && mx.IPAddresses.Count > 0)
foreach (IPAddress ip in mx.IPAddresses)
if (connectsmtp(ip, out smtpanswer))
goto CONNECTED;
}
else
{
foreach (IPAddress ip in ips)
if (connectsmtp(ip, out smtpanswer))
goto CONNECTED;
}
if (smtpanswer != String.Empty)
throw new MailServerException(smtpanswer);
throw new MailServerException(String.Format("All the mail servers of @{0} have been tried, but no response could be received.", resDom));
CONNECTED:
m_Client.SayHello(HeloDomain);
if (UseSsl && m_Client.StartTls(true))
{
m_Client.SayHello(HeloDomain); // say hello again.
}
if (m_Client.Login(mi.MailServerUserName, mi.MailServerPassword, mi.encoder))
{
OnAuthenticated(EventArgs.Empty);
}
if (!m_Client.MailFrom(mi.From))
throw new MailServerException(m_Client.LastResponse);
}
private bool connectsmtp(IPAddress ip, out string error)
{
error = String.Empty;
bool ret = false;
if (ip != null)
{
try
{
IPEndPoint remote = new IPEndPoint(ip, Port);
m_Client = new SmtpClient(remote, LocalPoint, UseLog);
OnConnect(ip.ToString());
ret = true;
}
catch (Exception e)
{
error = e.Message;
if (m_Client != null)
{
m_Client.Close();
m_Client = null;
}
}
}
return ret;
}
private int addrecipients()
{
int rcptcount = 0;
foreach (Recipient rec in mi.Recipients)
{
bool isok = m_Client.RcptTo(rec.Email);
if (isok) ++rcptcount;
rec.valid = isok;
rec.code = m_Client.LastCode;
rec.answer = m_Client.LastResponse;
}
OnRecipientsAdded(mi.Recipients);
if (rcptcount > 0)
OnReadyToSendMassMail(EventArgs.Empty);
return rcptcount;
}
private void senddata(string __to, bool forcedclose, int rcptcount, out bool datasentx)
{
datasentx = false;
mi.sent = false;
if (!mi.SendMail)
return; //noerr
try
{
if (forcedclose)
{
if (rcptcount == 0)
{
if (mi.Recipients.Count == 1)
throw new Exception(m_Client.LastResponse);
else
throw new Exception(String.Format(
"Since the mail server rejected all of the recipients (Total={0}), e-mail data cannot be transmitted.",
mi.Recipients.Count));
}
if (mi.Body != null && mi.Body.Length > MaxLength)
throw new Exception(String.Format(
"Size of message is {0} bytes. Maximum {1} bytes are allowed.",
mi.Body.Length, MaxLength));
}
if (!m_Client.StartData())
throw new MailServerException(m_Client.LastResponse);
string header = mi.ToString(__to, rcptcount);
sendbuffereddata(header);
if (m_Client.SendAndReceive(null) != Erle.SmtpClient.Commands.Ok)
throw new MailServerException(m_Client.LastResponse);
datasentx = true;
mi.sent = true;
datasent = true;
if (forcedclose)
OnSent(EventArgs.Empty);
}
catch (Exception exc)
{
if (forcedclose)
((IDisposable)this).Dispose();
throw new MailServerException(exc.Message);
}
}
private void sendbuffereddata(string header)
{
try
{
byte[] buffer = mi.encoder.GetBytes(header);
m_Client.Write(buffer, 0, buffer.Length);
int len;
if (mi.Body == null || (len = mi.Body.Length) <= 0)
goto FINISH;
int tosend;
int remain = len;
int totalsent = 0;
bool finalbuffer = false;
char[] buffchar = new char[MaxBuffer];
LOOP:
if (remain > MaxBuffer)
tosend = MaxBuffer;
else
{
tosend = remain;
finalbuffer = true;
}
mi.Body.CopyTo(totalsent, buffchar, 0, tosend);
buffer = MIME.QPEncode(
mi.encoder.GetBytes(buffchar, 0, tosend),
finalbuffer ? SmtpEncode.All : SmtpEncode.Dot
);
m_Client.Write(buffer, 0, buffer.Length);
totalsent += tosend;
remain -= tosend;
OnSendProgress(totalsent, remain);
buffer = null;
if ((totalsent < len) && m_Client.Poll(500, System.Net.Sockets.SelectMode.SelectWrite))
{
goto LOOP;
}
buffchar = null;
FINISH:
len = 0;
}
finally
{
try
{
if (m_Client != null && m_Client.Poll(TimeOut, System.Net.Sockets.SelectMode.SelectWrite))
m_Client.Write(crlf_dot_crlf, 0, crlf_dot_crlf.Length);
}
catch { }
}
}
#endregion
}
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -