Click here to Skip to main content
15,891,621 members
Articles / Programming Languages / C#

SMTP and POP3 Mail Server

Rate me:
Please Sign up or sign in to vote.
4.88/5 (96 votes)
29 Sep 20031 min read 1M   18.9K   315  
An SMTP and POP3 mail server written using the .NET Framework and C#.
using System;
using System.IO;
using LumiSoft.Net.Mime;

namespace LumiSoft.Net.IMAP.Server
{
	/// <summary>
	/// Summary description for FetchHelper.
	/// </summary>
	internal class FetchHelper
	{
		// ToDo: functions to accept MimeParser

		#region function ParseEnvelope

		public static string ParseEnvelope(byte[] data)
		{
			/* Rfc 3501 7.4.2
				ENVELOPE
				A parenthesized list that describes the envelope structure of a
				message.  This is computed by the server by parsing the
				[RFC-2822] header into the component parts, defaulting various
				fields as necessary.

				The fields of the envelope structure are in the following
				order: date, subject, from, sender, reply-to, to, cc, bcc,
				in-reply-to, and message-id.  The date, subject, in-reply-to,
				and message-id fields are strings.  The from, sender, reply-to,
				to, cc, and bcc fields are parenthesized lists of address
				structures.

				An address structure is a parenthesized list that describes an
				electronic mail address.  The fields of an address structure
				are in the following order: personal name, [SMTP]
				at-domain-list (source route), mailbox name, and host name.

				[RFC-2822] group syntax is indicated by a special form of
				address structure in which the host name field is NIL.  If the
				mailbox name field is also NIL, this is an end of group marker
				(semi-colon in RFC 822 syntax).  If the mailbox name field is
				non-NIL, this is a start of group marker, and the mailbox name
				field holds the group name phrase.

				If the Date, Subject, In-Reply-To, and Message-ID header lines
				are absent in the [RFC-2822] header, the corresponding member
				of the envelope is NIL; if these header lines are present but
				empty the corresponding member of the envelope is the empty
				string.
			*/
			// ((sender))
			// ENVELOPE ("date" "subject" from sender reply-to to cc bcc in-reply-to "messageID")

			MimeParser p = new MimeParser(data);

			string envelope  = "ENVELOPE (";
			
			// date
			envelope += "\"" + p.MessageDate.ToString("r",System.Globalization.DateTimeFormatInfo.InvariantInfo) + "\" ";
			
			// subject
			envelope += "\"" + p.Subject + "\" ";

			// from
			// ToDo: May be multiple senders
			LumiSoft.Net.Mime.Parser.eAddress adr = new LumiSoft.Net.Mime.Parser.eAddress(p.From);
			envelope += "((\"" + adr.Name + "\" NIL \"" + adr.Mailbox + "\" \"" + adr.Domain + "\")) ";

			// sender
			// ToDo: May be multiple senders
			envelope += "((\"" + adr.Name + "\" NIL \"" + adr.Mailbox + "\" \"" + adr.Domain + "\")) ";

			// reply-to
			string replyTo = MimeParser.ParseHeaderField("reply-to:",p.Headers);
			if(replyTo.Length > 0){
				envelope += "(";
				foreach(string recipient in replyTo.Split(';')){
					LumiSoft.Net.Mime.Parser.eAddress adrTo = new LumiSoft.Net.Mime.Parser.eAddress(recipient);
					envelope += "(\"" + adrTo.Name + "\" NIL \"" + adrTo.Mailbox + "\" \"" + adrTo.Domain + "\") ";
				}
				envelope = envelope.TrimEnd();
				envelope += ") ";
			}
			else{
				envelope += "NIL ";				
			}

			// to
			string[] to = p.To;
			envelope += "(";
			foreach(string recipient in to){
				LumiSoft.Net.Mime.Parser.eAddress adrTo = new LumiSoft.Net.Mime.Parser.eAddress(recipient);
				envelope += "(\"" + adrTo.Name + "\" NIL \"" + adrTo.Mailbox + "\" \"" + adrTo.Domain + "\") ";
			}
			envelope = envelope.TrimEnd();
			envelope += ") ";

			// cc
			string cc = MimeParser.ParseHeaderField("CC:",p.Headers);
			if(cc.Length > 0){
				envelope += "(";
				foreach(string recipient in cc.Split(';')){
					LumiSoft.Net.Mime.Parser.eAddress adrTo = new LumiSoft.Net.Mime.Parser.eAddress(recipient);
					envelope += "(\"" + adrTo.Name + "\" NIL \"" + adrTo.Mailbox + "\" \"" + adrTo.Domain + "\") ";
				}
				envelope = envelope.TrimEnd();
				envelope += ") ";
			}
			else{
				envelope += "NIL ";				
			}

			// bcc
			string bcc = MimeParser.ParseHeaderField("BCC:",p.Headers);
			if(bcc.Length > 0){
				envelope += "(";
				foreach(string recipient in bcc.Split(';')){
					LumiSoft.Net.Mime.Parser.eAddress adrTo = new LumiSoft.Net.Mime.Parser.eAddress(recipient);
					envelope += "(\"" + adrTo.Name + "\" NIL \"" + adrTo.Mailbox + "\" \"" + adrTo.Domain + "\") ";
				}
				envelope = envelope.TrimEnd();
				envelope += ") ";
			}
			else{
				envelope += "NIL ";				
			}

			// in-reply-to
			string inReplyTo = MimeParser.ParseHeaderField("in-reply-to:",p.Headers);
			if(inReplyTo.Length > 0){
				envelope += "\"" + inReplyTo + "\"";
			}
			else{
				envelope += "NIL ";
			}

			// message-id
			if(p.MessageID.Length > 0){
				envelope += "\"" + p.MessageID + "\"";
			}
			else{
				envelope += "NIL";
			}

			envelope += ")";

			return envelope;
		}

		#endregion

		#region function GetHeader

		public static byte[] GetHeader(byte[] data)
		{
			using(MemoryStream strm = new MemoryStream(data)){
				TextReader reader = (TextReader)new StreamReader(strm);				
				string headerStr = "";

				string line = reader.ReadLine();
				while(line != null){				
					// End of header reached
					if(line.Length == 0){
						break;
					}

					headerStr += line + "\r\n";

					line = reader.ReadLine();
				}
		
				return System.Text.Encoding.ASCII.GetBytes(headerStr);
			}
		}

		#endregion

		#region function ParseHeaderFields

		/// <summary>
		/// Returns requested header fields lines.
		/// </summary>
		/// <param name="fieldsStr">Header fields to get.</param>
		/// <param name="data">Message data.</param>
		/// <returns></returns>
		public static string ParseHeaderFields(string fieldsStr,byte[] data)
		{
			string retVal = "";

			string[] fields = fieldsStr.Split(' ');
            using(MemoryStream mStrm = new MemoryStream(data)){
				TextReader r = new StreamReader(mStrm);
				string line = r.ReadLine();
				
				bool fieldFound = false;
				// Loop all header lines
				while(line != null){ 
					// End of header
					if(line.Length == 0){
						break;
					}

					// Field continues
					if(fieldFound && line.StartsWith("\t")){
						retVal += line + "\r\n";
					}
					else{
						fieldFound = false;

						// Check if wanted field
						foreach(string field in fields){
							if(line.Trim().ToLower().StartsWith(field.Trim().ToLower())){
								retVal += line + "\r\n";
								fieldFound = true;
							}
						}
					}

					line = r.ReadLine();
				}
			}

			return retVal;
		}

		#endregion

		#region function ParseHeaderFieldsNot

		/// <summary>
		/// Returns header fields lines except requested.
		/// </summary>
		/// <param name="fieldsStr">Header fields to skip.</param>
		/// <param name="data">Message data.</param>
		/// <returns></returns>
		public static string ParseHeaderFieldsNot(string fieldsStr,byte[] data)
		{
			string retVal = "";

			string[] fields = fieldsStr.Split(' ');
            using(MemoryStream mStrm = new MemoryStream(data)){
				TextReader r = new StreamReader(mStrm);
				string line = r.ReadLine();
				
				bool fieldFound = false;
				// Loop all header lines
				while(line != null){ 
					// End of header
					if(line.Length == 0){
						break;
					}

					// Filed continues
					if(fieldFound && line.StartsWith("\t")){
						retVal += line + "\r\n";
					}
					else{
						fieldFound = false;

						// Check if wanted field
						foreach(string field in fields){
							if(line.Trim().ToLower().StartsWith(field.Trim().ToLower())){								
								fieldFound = true;
							}
						}

						if(!fieldFound){
							retVal += line + "\r\n";
						}
					}

					line = r.ReadLine();
				}
			}

			return retVal;
		}

		#endregion

		#region function ParseText

		/// <summary>
		/// Parses body text from message
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		public static string ParseText(byte[] data)
		{
			MimeParser p = new MimeParser(data);

			return p.BodyText;
		}

		#endregion

		#region function ParseMimeEntry

		/// <summary>
		/// Returns requested mime entry data.
		/// </summary>
		/// <param name="message"></param>
		/// <param name="mimeEntryNo"></param>
		/// <returns>Returns requested mime entry data or NULL if requested entri doesn't exist.</returns>
		public static byte[] ParseMimeEntry(byte[] message,int mimeEntryNo)
		{
			MimeParser p = new MimeParser(message);

			if(mimeEntryNo > 0 && mimeEntryNo <= p.MimeEntries.Count){
				return ((MimeEntry)p.MimeEntries[mimeEntryNo - 1]).Data;
			}

			return null;
		}

		#endregion

	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Estonia Estonia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions