private void Data(SMTPContext context) { context.WriteLine(MESSAGE_START_DATA); SMTPMessage message = context.Message; IPEndPoint clientEndPoint = (IPEndPoint)context.Socket.RemoteEndPoint; StringBuilder header = new StringBuilder(); header.Append(String.Format("Received: from {0} ({0} [{1}])", context.ClientDomain, clientEndPoint.Address)); header.Append("\r\n"); header.Append(String.Format(" by {0} (Eric Daugherty's C# Email Server)", domain)); header.Append("\r\n"); header.Append(" " + System.DateTime.Now); header.Append("\r\n"); message.AddData(header.ToString()); String line = context.ReadLine(); while (!line.Equals(".")) { message.AddData(line); message.AddData("\r\n"); line = context.ReadLine(); } // Spool the message messageSpool.SpoolMessage(message); context.WriteLine(MESSAGE_OK); // Reset the connection. context.Reset(); }
/// <summary> /// Handle the RCPT TO:<address> command. /// </summary> private void Rcpt(SMTPContext context, string argument) { if (context.LastCommand == COMMAND_MAIL || context.LastCommand == COMMAND_RCPT) { string address = ParseAddress(argument); if (address != null) { try { EmailAddress emailAddress = new EmailAddress(address); // Check to make sure we want to accept this message. if (recipientFilter.AcceptRecipient(context, emailAddress)) { context.Message.AddToAddress(emailAddress); context.LastCommand = COMMAND_RCPT; context.WriteLine(MESSAGE_OK); if (log.IsDebugEnabled) { log.Debug(String.Format("Connection {0}: RcptTo address: {1} accepted.", context.ConnectionId, address)); } } else { context.WriteLine(MESSAGE_UNKNOWN_USER); if (log.IsDebugEnabled) { log.Debug(String.Format("Connection {0}: RcptTo address: {1} rejected. Did not pass Address Filter.", context.ConnectionId, address)); } } } catch (InvalidEmailAddressException) { if (log.IsDebugEnabled) { log.Debug(String.Format("Connection {0}: RcptTo argument: {1} rejected. Should be from:<*****@*****.**>", context.ConnectionId, argument)); } context.WriteLine(MESSAGE_INVALID_ADDRESS); } } else { if (log.IsDebugEnabled) { log.Debug(String.Format("Connection {0}: RcptTo argument: {1} rejected. Should be from:<*****@*****.**>", context.ConnectionId, argument)); } context.WriteLine(MESSAGE_INVALID_ADDRESS); } } else { context.WriteLine(MESSAGE_INVALID_COMMAND_ORDER); } }
/// <summary> /// Reset the connection state. /// </summary> private void Rset(SMTPContext context) { if (context.LastCommand != -1) { // Dump the message and reset the context. context.Reset(); context.WriteLine(MESSAGE_OK); } else { context.WriteLine(MESSAGE_INVALID_COMMAND_ORDER); } }
/// <summary> /// Handle the MAIL FROM:<address> command. /// </summary> private void Mail(SMTPContext context, string argument) { bool addressValid = false; if (context.LastCommand == COMMAND_HELO) { string address = ParseAddress(argument); if (address != null) { try { EmailAddress emailAddress = new EmailAddress(address); context.Message.FromAddress = emailAddress; context.LastCommand = COMMAND_MAIL; addressValid = true; context.WriteLine(MESSAGE_OK); if (log.IsDebugEnabled) { log.Debug(String.Format("Connection {0}: MailFrom address: {1} accepted.", context.ConnectionId, address)); } } catch (InvalidEmailAddressException) { // This is fine, just fall through. } } // If the address is invalid, inform the client. if (!addressValid) { if (log.IsDebugEnabled) { log.Debug(String.Format("Connection {0}: MailFrom argument: {1} rejected. Should be from:<*****@*****.**>", context.ConnectionId, argument)); } context.WriteLine(MESSAGE_INVALID_ADDRESS); } } else { context.WriteLine(MESSAGE_INVALID_COMMAND_ORDER); } }
/// <summary> /// Handles the HELO command. /// </summary> private void Helo(SMTPContext context, String[] inputs) { if (context.LastCommand == -1) { if (inputs.Length == 2) { context.ClientDomain = inputs[1]; context.LastCommand = COMMAND_HELO; context.WriteLine(HeloResponse); } else { context.WriteLine(MESSAGE_INVALID_ARGUMENT_COUNT); } } else { context.WriteLine(MESSAGE_INVALID_COMMAND_ORDER); } }
/// <summary> /// ProcessConnection handles a connected TCP Client /// and performs all necessary interaction with this /// client to comply with RFC821. This method is thread /// safe. /// </summary> public void ProcessConnection(Socket socket) { long currentConnectionId = 0; // Really only need to lock on the long, but that is not // allowed. Is there a better way to do this? lock (this) { currentConnectionId = connectionId++; } SMTPContext context = new SMTPContext(currentConnectionId, socket); try { SendWelcomeMessage(context); ProcessCommands(context); } catch (Exception exception) { log.Error(String.Format("Connection {0}: Error: {1}", context.ConnectionId, exception), exception); } }
/// <summary> /// Accepts only local email. /// </summary> /// <param name='context'>The SMTPContext</param> /// <param name='recipient'>TODO - add parameter description</param> public virtual bool AcceptRecipient(SMTPContext context, EmailAddress recipient) { return(domain.Equals(recipient.Domain)); }
/// <summary> /// Handles the command input from the client. This /// message returns when the client issues the quit command. /// </summary> private void ProcessCommands(SMTPContext context) { bool isRunning = true; String inputLine; // Loop until the client quits. while (isRunning) { try { inputLine = context.ReadLine(); if (inputLine == null) { isRunning = false; context.Close(); continue; } log.Debug("ProcessCommands Read: " + inputLine); String[] inputs = inputLine.Split(" ".ToCharArray()); switch (inputs[0].ToLower()) { case "helo": Helo(context, inputs); break; case "rset": Rset(context); break; case "noop": context.WriteLine(MESSAGE_OK); break; case "quit": isRunning = false; context.WriteLine(MESSAGE_GOODBYE); context.Close(); break; case "mail": if (inputs[1].ToLower().StartsWith("from")) { Mail(context, inputLine.Substring(inputLine.IndexOf(" "))); break; } context.WriteLine(MESSAGE_UNKNOWN_COMMAND); break; case "rcpt": if (inputs[1].ToLower().StartsWith("to")) { Rcpt(context, inputLine.Substring(inputLine.IndexOf(" "))); break; } context.WriteLine(MESSAGE_UNKNOWN_COMMAND); break; case "data": Data(context); break; default: context.WriteLine(MESSAGE_UNKNOWN_COMMAND); break; } } catch (Exception exception) { log.Error(String.Format("Connection {0}: Exception occured while processing commands: {1}", context.ConnectionId, exception), exception); context.WriteLine(MESSAGE_SYSTEM_ERROR); } } }
/// <summary> /// Sends the welcome greeting to the client. /// </summary> private void SendWelcomeMessage(SMTPContext context) { context.WriteLine(WelcomeMessage); }