/// <summary> /// Saves the email to the local drop folder. /// </summary> private async Task <SmtpServerTransactionAsyncResult> SaveToLocalMailboxAsync() { // Add the MAIL FROM & RCPT TO headers. Data = MessageManager.AddHeader(Data, new MessageHeader("X-Reciepient", string.Join("; ", RcptTo))); if (HasMailFrom && string.IsNullOrWhiteSpace(MailFrom)) { Data = MessageManager.AddHeader(Data, new MessageHeader("X-Sender", "<>")); } else { Data = MessageManager.AddHeader(Data, new MessageHeader("X-Sender", MailFrom)); } // Need to drop a copy of the message for each recipient. for (int i = 0; i < RcptTo.Count; i++) { // Put the messages in a subfolder for each recipient. // Unless the rcpt to is a return path message in which case put them all in a return-path folder string mailDirPath = string.Empty; // Bounce. if (RcptTo[i].StartsWith("return-", StringComparison.OrdinalIgnoreCase)) { mailDirPath = MtaParameters.BounceDropFolder; } // Abuse. else if (RcptTo[i].StartsWith("abuse@", StringComparison.OrdinalIgnoreCase)) { mailDirPath = MtaParameters.AbuseDropFolder; } // Postmaster. else if (RcptTo[i].StartsWith("postmaster@", StringComparison.OrdinalIgnoreCase)) { mailDirPath = MtaParameters.PostmasterDropFolder; } // Must be feedback loop. else { mailDirPath = MtaParameters.FeedbackLoopDropFolder; } // Ensure the directory exists by always calling create. Directory.CreateDirectory(mailDirPath); // Write the Email File. using (StreamWriter sw = new StreamWriter(Path.Combine(mailDirPath, Guid.NewGuid().ToString()) + ".eml")) { await sw.WriteAsync(Data); } } return(SmtpServerTransactionAsyncResult.SuccessMessageDelivered); }
public void AddHeader() { string msg = @"Received: by mail-ve0-f170.google.com with SMTP id c14so7342138vea.29 for <*****@*****.**>; Thu, 12 Sep 2013 08:55:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:date:message-id:subject:from:to :content-type; bh=g3zLYH4xKxcPrHOD18z9YfpQcnk/GaJedfustWU5uGs=; b=QQp2spZaT8t1uP2qlmFDNRy5SMCkPfyAcwWAyTH8SbWtBMZ6hSssOHTdYEPb6aPbBQ qFquL9n20dtfSLU47+OLtB+cOoOtAt1FACRWN42x/V608OEAeu25KjTgnD3LFBvn482y PWmlpv8MlyulZvqT33dgp0C7Wb4HN5jGLgRajteAFfyiK+Hn0ouP+Q/WdWFm3SAiB4e2 VVEPV+8hh79e3Bpwqjjnlu3xL8gG+kgqGKnzv7XsuSH7QdO7KDiVQLiWqvPv3je15eN5 6fQW6hfnD9vU3oJtu4Qxnxw2LCSC8Ble2JVIqFuVlljwzVERv00b8GlpMUy4VoSv/oxZ jR9Q== X-Gm-Message-State: ALoCoQkJ3V6JKWYCk5sVgPWozY51PLGpZk+oEFXvfjTeRXLdEwuyJt1ZZGIF8VY7cV9ZQkkKm5/U MIME-Version: 1.0 X-Received: by 10.58.207.103 with SMTP id lv7mr1139399vec.33.1379000866633; Thu, 12 Sep 2013 08:47:46 -0700 (PDT) Received: by 10.221.57.135 with HTTP; Thu, 12 Sep 2013 08:47:46 -0700 (PDT) Date: Thu, 12 Sep 2013 16:47:46 +0100 Message-ID: <*****@*****.**> Subject: test From: Redacted <*****@*****.**> To: [email protected] Content-Type: text/plain; charset=UTF-8 test"; // Test with header value thats short enougth to not need folding. string returned = MessageManager.AddHeader(msg, new MessageHeader("Test", "test")); Assert.AreEqual("Test: test" + System.Environment.NewLine + msg, returned); // Test with header value that is longer than 78 but can't be folded as it contains no white space. returned = MessageManager.AddHeader(msg, new MessageHeader("Test", "testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest")); Assert.AreEqual(@"Test: testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" + System.Environment.NewLine + msg, returned); // Test with long value that can be folded. returned = MessageManager.AddHeader(msg, new MessageHeader("Test", "test testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest")); Assert.AreEqual(@"Test: test testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest" + System.Environment.NewLine + msg, returned); }
/// <summary> /// Adds a header to the message data. /// </summary> /// <param name="name">The header name.</param> /// <param name="value">Value for the header.</param> public void AddHeader(string name, string value) { Data = MessageManager.AddHeader(Data, new MessageHeader(name, value)); }
/// <summary> /// Queues the email for relaying. /// </summary> private async Task <SmtpServerTransactionAsyncResult> QueueForRelayingAsync() { // The email is for relaying. Guid messageID = Guid.NewGuid(); // Look for any MTA control headers. MessageHeaderCollection headers = MessageManager.GetMessageHeaders(Data); // Will not be null if the SendGroupID header was present. MessageHeader ipGroupHeader = headers.SingleOrDefault(m => m.Name.Equals(MessageHeaderNames.SendGroupID, StringComparison.OrdinalIgnoreCase)); // Parameter will hold the MtaIPGroup that will be used to relay this message. VirtualMta.VirtualMtaGroup mtaGroup = null; int ipGroupID = 0; if (ipGroupHeader != null) { if (int.TryParse(ipGroupHeader.Value, out ipGroupID)) { mtaGroup = VirtualMta.VirtualMtaManager.GetVirtualMtaGroup(ipGroupID); } } #region Look for a send id, if one doesn't exist create it. MessageHeader sendIdHeader = headers.SingleOrDefault(h => h.Name.Equals(MessageHeaderNames.SendID, StringComparison.OrdinalIgnoreCase)); int internalSendId = -1; if (sendIdHeader != null) { Sends.Send sndID = await Sends.SendManager.Instance.GetSendAsync(sendIdHeader.Value); if (sndID.SendStatus == SendStatus.Discard) { return(SmtpServerTransactionAsyncResult.FailedSendDiscarding); } internalSendId = sndID.InternalID; } else { Sends.Send sndID = await Sends.SendManager.Instance.GetDefaultInternalSendIdAsync(); if (sndID.SendStatus == SendStatus.Discard) { return(SmtpServerTransactionAsyncResult.FailedSendDiscarding); } internalSendId = sndID.InternalID; } #endregion #region Generate Return Path string returnPath = string.Empty; // Can only return path to messages with one rcpt to if (RcptTo.Count == 1) { // Need to check to see if the message contains a return path overide domain. MessageHeader returnPathDomainOverrideHeader = headers.SingleOrDefault(h => h.Name.Equals(MessageHeaderNames.ReturnPathDomain, StringComparison.OrdinalIgnoreCase)); if (returnPathDomainOverrideHeader != null && MtaParameters.LocalDomains.Count(d => d.Hostname.Equals(returnPathDomainOverrideHeader.Value, StringComparison.OrdinalIgnoreCase)) > 0) { // The message contained a local domain in the returnpathdomain // header so use it instead of the default. returnPath = ReturnPathManager.GenerateReturnPath(RcptTo[0], internalSendId, returnPathDomainOverrideHeader.Value); } else { // The message didn't specify a return path overide or it didn't // contain a localdomain so use the default. returnPath = ReturnPathManager.GenerateReturnPath(RcptTo[0], internalSendId); } // Insert the return path header. Data = MessageManager.AddHeader(Data, new MessageHeader("Return-Path", "<" + returnPath + ">")); } else { // multiple rcpt's so can't have unique return paths, use generic mail from. returnPath = MailFrom; } #endregion #region Generate a message ID header string msgIDHeaderVal = "<" + messageID.ToString("N") + MailFrom.Substring(MailFrom.LastIndexOf("@")) + ">"; // If there is already a message header, remove it and add our own. required for feedback loop processing. if (headers.Count(h => h.Name.Equals("Message-ID", StringComparison.OrdinalIgnoreCase)) > 0) { Data = MessageManager.RemoveHeader(Data, "Message-ID"); } // Add the new message-id header. Data = MessageManager.AddHeader(Data, new MessageHeader("Message-ID", msgIDHeaderVal)); #endregion // Remove any control headers. headers = new MessageHeaderCollection(headers.Where(h => h.Name.StartsWith(MessageHeaderNames.HeaderNamePrefix, StringComparison.OrdinalIgnoreCase))); foreach (MessageHeader header in headers) { Data = MessageManager.RemoveHeader(Data, header.Name); } // If the MTA group doesn't exist or it's not got any IPs, use the default. if (mtaGroup == null || mtaGroup.VirtualMtaCollection.Count == 0) { ipGroupID = VirtualMta.VirtualMtaManager.GetDefaultVirtualMtaGroup().ID; } // Attempt to Enqueue the Email for Relaying. if (!QueueManager.Instance.Enqueue(messageID, ipGroupID, internalSendId, returnPath, RcptTo.ToArray(), Data)) { return(SmtpServerTransactionAsyncResult.FailedToEnqueue); } return(SmtpServerTransactionAsyncResult.SuccessMessageQueued); }