⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dnsmail.cs

📁 A project written in C# sends email without smtp server. It queries dns server for mx records and se
💻 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 + -