jstedfast / MimeKit

A .NET MIME creation and parser library with support for S/MIME, PGP, DKIM, TNEF and Unix mbox spools.
http://www.mimekit.net
MIT License
1.83k stars 371 forks source link

DKIM failures on html body larger than 1000 characters? #272

Closed JT3 closed 8 years ago

JT3 commented 8 years ago

I am not 100% sure if this is on the MimeKit side, or my IIS 7.5 SMTP server. Any guidance is appreciated.

I am using Mimekit to create messages in a c# console app and sending via mailkit. All initial testing was with short body messages, and it worked beautifully. Thanks. Moving to more complex messages with inline images caused the dkim signing to show as invalid, and narrowed it down to length as the contributing factor.

The following string set as the htmlbody with builder is successful. Taking the string up to 1000 characters causes the signing to fail validation at gmail, as does port 25's auth-results parser.

Is there a different way I need to handle the message when signing?

``port25.com response:


DKIM check details:

Result: fail (wrong body hash: expected gQIDnZMTIOJXgVlhGQosQSJed0WsEJCUX7NtA696CWs=) ID(s) verified: Canonicalized Headers:

My code

` private static void sendDKIMmessage(todetail t, string _conn) { //http://www.mimekit.net/docs/html/CreatingMessages.htm MimeMessage m = new MimeMessage(); m.To.Add(new MailboxAddress(t.email, t.email));

        foreach (string c in cclist)
        {
            m.Cc.Add(new MailboxAddress(c, c));
        }
        foreach (string b in bcclist)
        {
            m.Cc.Add(new MailboxAddress(b, b));
        }

        var builder = new BodyBuilder();
        m.Subject = subject;

        if (!t.body.Contains("<html>"))
        {
            t.body = "<html>" + t.body + "</html>";
        }

        string strlong = "<html><body>fffffffffffff ffffffffffff fffffffffffffffff ffffffffffff aaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaa cccccccccccc ccccccccccccccccc vvvvvvvvvvvvvvvv bbbbbbbbbbbbbbbbb nnnnnnnnnnnnnnnn mmmmmmmmmmmmmmmmmm aaaaaaaaaaaaaaaaaaaaaaaaaas ssssssssssssssssssssssssssssssss dddddddddddddddddddddddddddddddddd ffffffffffffffffffffffffffffffffffff gggggggggggggggggggggggggggggggg hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr ttttttttttttttttttttttttttttttttttttttttttttttttttt 444444444444444444444444444444444444444444444444 1111111111111111111111111111111111111111111 22222222222222222222222222222222222222222222222222222 aaaaaaaaaaazzzzzzzzzzzzzzzzzzz xxxxxxxxxxxxxxxxxxxx ccccccccccccccccccccccc vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb hhhhhhhhhhhhhhh yyyyyyyyyyyyyy</body></html>";
        builder.HtmlBody = strlong;

        m.Body = builder.ToMessageBody();
        m.Sender = new MailboxAddress(fromfriendly, fromemail);
        m.InReplyTo = fromemail;
        m.From.Add(new MailboxAddress(fromfriendly, fromemail));

        Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;

        m.MessageId = classid + "_" + t.addressid.ToString() + "." + unixTimestamp + "@xxxxxx.com";

        var headersToSign = new[] { HeaderId.From, HeaderId.To, HeaderId.Subject, HeaderId.Date, HeaderId.MessageId };
        var signer = new DkimSigner(System.Configuration.ConfigurationManager.AppSettings["xxxDKIM"], "xxxxxx.com", "xxxx");

        //   m.To.Add(new MailboxAddress("check-auth@verifier.port25.com", "check-auth@verifier.port25.com"));

        m.Sign(signer, headersToSign,
            DkimCanonicalizationAlgorithm.Relaxed,
            DkimCanonicalizationAlgorithm.Simple);

        using (MailKit.Net.Smtp.SmtpClient client = new MailKit.Net.Smtp.SmtpClient())
        {
            client.ServerCertificateValidationCallback = CustomCertificateValidationCallback;
            client.Connect("x.x.x.x", 25);
            client.AuthenticationMechanisms.Remove("XOAUTH2");

            client.Send(m);
            client.Disconnect(true);
        }
        //insert message into deployment history

    }

`

jstedfast commented 8 years ago

You need to call message.Prepare() before calling Sign() so that MIME parts get properly encoded. Either that or you need to specifically set the ContentTransferEncoding of each part.

Since there's no way for MimeKit to know what encoding constraints the SMTP server will have, it has no idea what encoding to use unless you tell it.

To be safe (and allow it to work with all SMTP servers), you can call message.Prepare (EncodingConstraint.SevenBit);