/// <summary> /// Signs the given mail item using the provided signer. The mailItem object will be updated so that it includes the signature. /// </summary> /// <param name="domainSigner">The domain and its signer</param> /// <param name="mailItem">The mail item to sign</param> /// <returns></returns> public void SignMessage(DomainElementSigner domainSigner, MailItem mailItem) { using (Stream stream = mailItem.GetMimeReadStream()) { stream.Seek(0, SeekOrigin.Begin); Logger.LogDebug("Parsing the MimeMessage"); MimeMessage message = MimeMessage.Load(stream, true); Logger.LogDebug("Signing the message"); lock (settingsMutex) { message.Sign(domainSigner.Signer, eligibleHeaders, headerCanonicalization, bodyCanonicalization); } var value = message.Headers[HeaderId.DkimSignature]; Logger.LogDebug("Got signing header: " + value); // we first need to create a memory stream, because if WriteTo is called with mailItem Stream directly, it throws an exception somehow. MemoryStream memoryOutputStream = new MemoryStream(); message.WriteTo(FormatOptions.Default, memoryOutputStream); memoryOutputStream.Seek(0, SeekOrigin.Begin); using (Stream outputStream = mailItem.GetMimeWriteStream()) { memoryOutputStream.WriteTo(outputStream); outputStream.Close(); } stream.Close(); } }
/// <summary> /// Signs the given mail item, if possible, according to the DKIM standard. /// </summary> /// <param name="mailItem">The mail item that is to be signed, if possible.</param> private void SignMailItem(MailItem mailItem) { // If the mail item is a "system message" then it will be read-only here, // and we can't sign it. Additionally, if the message has a "TnefPart", // then it is in a proprietary format used by Outlook and Exchange Server, // which means we shouldn't bother signing it. if (!mailItem.Message.IsSystemMessage && mailItem.Message.TnefPart == null) { /* Check if DKIM is defined for the current domain */ DomainElement domain = null; foreach (DomainElement e in domainSettings) { if (mailItem.FromAddress.DomainPart .ToUpperInvariant() .Contains(e.getDomain().ToUpperInvariant())) { domain = e; } } /* If domain was found in define domain configuration, we just do nothing */ if (domain != null) { using (var inputStream = mailItem.GetMimeReadStream()) { string dkim = this.dkimSigner.CanSign(domain, inputStream); if (dkim.Length != 0) { Logger.LogInformation("Signing mail with header: " + dkim); inputStream.Seek(0, SeekOrigin.Begin); byte[] inputBuffer = ReadFully(inputStream); inputStream.Close(); using (var outputStream = mailItem.GetMimeWriteStream()) { try { this.dkimSigner.Sign(inputBuffer, outputStream, dkim); } catch (Exception ex) { Logger.LogError("Signing went terribly wrong: " + ex.ToString()); } outputStream.Close(); } } } } } }
/// <summary> /// Signs the given mail item, if possible, according to the DKIM standard. /// </summary> /// <param name="mailItem">The mail item that is to be signed, if possible.</param> private void SignMailItem(MailItem mailItem) { // If the mail item is a "system message" then it will be read-only here, // and we can't sign it. Additionally, if the message has a "TnefPart", // then it is in a proprietary format used by Outlook and Exchange Server, // which means we shouldn't bother signing it. if (!mailItem.Message.IsSystemMessage && mailItem.Message.TnefPart == null) { using (var inputStream = mailItem.GetMimeReadStream()) { string dkim = this.dkimSigner.CanSign(inputStream); if (dkim.Length != 0) { string source = this.dkimSigner.SourceMessage(inputStream); inputStream.Close(); Logger.LogInformation("Signing mail with header: " + dkim); using (var outputStream = mailItem.GetMimeWriteStream()) { try { this.dkimSigner.Sign(source, outputStream, dkim); } catch (Exception ex) { Logger.LogError("Signing went terribly wrong: " + ex.ToString()); } outputStream.Close(); } } } } }
/// <summary> /// Signs the given mail item using the provided signer. The mailItem object will be updated so that it includes the signature. /// </summary> /// <param name="domainSigner">The domain and its signer</param> /// <param name="mailItem">The mail item to sign</param> /// <returns></returns> public void SignMessage(DomainElementSigner domainSigner, MailItem mailItem) { // MailItem.GetMimeWriteStream() internally uses // Microsoft.Exchange.Data.Mime.MimeDocument.GetLoadStream(), which may reformat the // message using different formatting than is originally read from // MailItem.GetMimeReadStream(). To prevent these formatting changes from invalidating // the DKIM signature, we must read then write then re-read the message to ensure that // any formatting changes are made before we sign the message. using (MemoryStream memStream = new MemoryStream()) { using (Stream inputStream = mailItem.GetMimeReadStream()) { inputStream.Seek(0, SeekOrigin.Begin); #if EX_2007_SP3 || EX_2010 || EX_2010_SP1 || EX_2010_SP2 || EX_2010_SP3 byte[] buffer = new byte[16 * 1024]; int size; while ((size = inputStream.Read(buffer, 0, buffer.Length)) > 0) { memStream.Write(buffer, 0, size); } #else inputStream.CopyTo(memStream); #endif } memStream.Seek(0, SeekOrigin.Begin); using (Stream outputStream = mailItem.GetMimeWriteStream()) { memStream.WriteTo(outputStream); } } using (Stream inputStream = mailItem.GetMimeReadStream()) { inputStream.Seek(0, SeekOrigin.Begin); Logger.LogDebug("Parsing the MimeMessage"); MimeMessage message = MimeMessage.Load(inputStream, true); // 'inputStream' cannot be disposed until we are done with 'message' Logger.LogDebug("Signing the message"); lock (settingsMutex) { message.Sign(domainSigner.Signer, eligibleHeaders, headerCanonicalization, bodyCanonicalization); } var value = message.Headers[HeaderId.DkimSignature]; Logger.LogDebug("Got signing header: " + value); // The Stream returned by mailItem.GetMimeWriteStream() will throw an exception if // Stream.Write() is called after Stream.Flush() has been called, but // MimeMessage.WriteTo(FormatOptions, Stream) may call Stream.Flush() before the full // message has been written. To avoid exceptions we must buffer the message in a // MemoryStream. using (MemoryStream memStream = new MemoryStream()) { message.WriteTo(FormatOptions.Default, memStream); memStream.Seek(0, SeekOrigin.Begin); using (Stream outputStream = mailItem.GetMimeWriteStream()) { memStream.WriteTo(outputStream); } } } }
/// <summary> /// Signs the given mail item using the provided signer. The mailItem object will be updated so that it includes the signature. /// </summary> /// <param name="domainSigner">The domain and its signer</param> /// <param name="mailItem">The mail item to sign</param> /// <returns></returns> public void SignMessage(DomainElementSigner domainSigner, MailItem mailItem) { if (disposed) throw new ObjectDisposedException("DkimSigner"); using (Stream stream = mailItem.GetMimeReadStream()) { stream.Seek(0, SeekOrigin.Begin); Logger.LogDebug("Parsing the MimeMessage"); MimeMessage message = MimeMessage.Load(stream, true); Logger.LogDebug("Signing the message"); lock (settingsMutex) { message.Sign(domainSigner.Signer, eligibleHeaders, headerCanonicalization, bodyCanonicalization); } var value = message.Headers[HeaderId.DkimSignature]; Logger.LogDebug("Got signing header: " + value); // we first need to create a memory stream, because if WriteTo is called with mailItem Stream directly, it throws an exception somehow. MemoryStream memoryOutputStream = new MemoryStream(); message.WriteTo(FormatOptions.Default, memoryOutputStream); memoryOutputStream.Seek(0, SeekOrigin.Begin); using (Stream outputStream = mailItem.GetMimeWriteStream()) { memoryOutputStream.WriteTo(outputStream); outputStream.Close(); } stream.Close(); } }
/// <summary> /// Signs the given mail item, if possible, according to the DKIM standard. /// </summary> /// <param name="mailItem">The mail item that is to be signed, if possible.</param> private void SignMailItem(MailItem mailItem) { // If the mail item is a "system message" then it will be read-only here, // and we can't sign it. Additionally, if the message has a "TnefPart", // then it is in a proprietary format used by Outlook and Exchange Server, // which means we shouldn't bother signing it. if (!mailItem.Message.IsSystemMessage && mailItem.Message.TnefPart == null) { /* Check if we have a valid From address */ if (!mailItem.FromAddress.IsValid || mailItem.FromAddress.DomainPart == null) { Logger.LogWarning("Invalid from address: '" + mailItem.FromAddress + "'. Not signing email."); return; } /* If domain was found in define domain configuration */ if (this.dkimSigner.GetDomains().ContainsKey(mailItem.FromAddress.DomainPart)) { DomainElement domain = this.dkimSigner.GetDomains()[mailItem.FromAddress.DomainPart]; using (Stream stream = mailItem.GetMimeReadStream()) { Logger.LogDebug("Domain found: '"+domain.Domain+"'. I'll sign the message."); string dkim = this.dkimSigner.CanSign(domain, stream); if (dkim.Length != 0) { Logger.LogInformation("Signing mail with header: " + dkim); stream.Seek(0, SeekOrigin.Begin); byte[] inputBuffer = ReadFully(stream); stream.Close(); using (Stream outputStream = mailItem.GetMimeWriteStream()) { try { this.dkimSigner.Sign(inputBuffer, outputStream, dkim); } catch (Exception ex) { Logger.LogError("Signing went terribly wrong: " + ex.ToString()); } outputStream.Close(); } } else { Logger.LogDebug("Got empty signing header. Something went wrong..."); } } } else { Logger.LogDebug("No entry found in config for domain '" + mailItem.FromAddress.DomainPart + "'"); } } else Logger.LogDebug("Message is a System message or of TNEF format. Not signing."); }
/// <summary> /// Signs the given mail item, if possible, according to the DKIM standard. /// </summary> /// <param name="mailItem">The mail item that is to be signed, if possible.</param> private void SignMailItem(MailItem mailItem) { // If the mail item is a "system message" then it will be read-only here, // and we can't sign it. Additionally, if the message has a "TnefPart", // then it is in a proprietary format used by Outlook and Exchange Server, // which means we shouldn't bother signing it. if (!mailItem.Message.IsSystemMessage && mailItem.Message.TnefPart == null) { /* Check if DKIM is defined for the current domain */ DomainElement domain = null; foreach (DomainElement e in domainSettings) { if (mailItem.FromAddress.DomainPart .ToUpperInvariant() .Contains(e.getDomain().ToUpperInvariant())) domain = e; } /* If domain was found in define domain configuration, we just do nothing */ if (domain != null) { using (var inputStream = mailItem.GetMimeReadStream()) { string dkim = this.dkimSigner.CanSign(domain, inputStream); if (dkim.Length != 0) { Logger.LogInformation("Signing mail with header: " + dkim); inputStream.Seek(0, SeekOrigin.Begin); byte[] inputBuffer = ReadFully(inputStream); inputStream.Close(); using (var outputStream = mailItem.GetMimeWriteStream()) { try { this.dkimSigner.Sign(inputBuffer, outputStream, dkim); } catch (Exception ex) { Logger.LogError("Signing went terribly wrong: " + ex.ToString()); } outputStream.Close(); } } } } } }