【问题标题】:MimeMessage causing recipient address required error in Gmail Apis possibly due base64url encodingMimeMessage 导致 Gmail API 中需要收件人地址错误可能是由于 base64url 编码
【发布时间】:2021-11-03 22:45:12
【问题描述】:

编辑 1:在进一步玩之后,似乎空间不是罪魁祸首,但可能是 base64url 编码方法。我提取了纯文本和 mime 消息的原始字符串,并在在线 tool 中进行了比较。在纯文本的情况下,它们都是相同的,但在 mime 消息的情况下,它们是完全不同的,但是如果我将它们解码回字符串,它们是相同的。我对编码解码知之甚少,因此将不胜感激。 编辑结束。

我正在尝试使用 mimekit 在 c# 中撰写电子邮件并使用 google.apis.gmail.v1 发送。但它会抛出错误“需要收件人地址[400]。这是代码。

var mailMessage = new MailMessage
            {
                Subject = "test subject",
                Body = " <h1>test body</h1>"
            };
            mailMessage.IsBodyHtml = true;
            mailMessage.To.Add("testemail");

            MimeMessage mm = MimeMessage.CreateFromMailMessage(mailMessage);
            var gmailMessage = new Google.Apis.Gmail.v1.Data.Message
            {
                Raw = Base64UrlEncode(mm.ToString())
            };
            service.Users.Messages.Send(gmailMessage, "me").execute();
            // Encoding method
             public static string Base64UrlEncode(string text)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(text);

            return Convert.ToBase64String(bytes)
                .Replace('+', '-')
                .Replace('/', '_')
                .Replace("=", "");
        }

上面的代码会抛出错误,但是如果我使用如下纯文本撰写电子邮件:

string plainText = "To:testemail\r\n" +
                        "Subject: test subject\r\n" +
                        "Content-Type: text/html; charset=us-ascii\r\n\r\n" +
                        "<h1>Test body<h1>";

如果我将此纯文本编码并传递给 gmail 消息的 Raw 属性,这将完美无缺。 为了调试问题,我使用在线工具解码了纯文本和 mime 消息,我注意到的唯一区别是 To 标头值之前的空格,如下所示:

// plain text:
To:testemail

//mime message:
To: testemail

注意“To:”后面的空格。为了证实我的怀疑,我从 mime 消息中删除了空格并使用在线工具再次对其进行编码,并将编码的字符串传递给 Raw 属性,它可以正常工作。所以想出了一个hacky解决方案并尝试使用正则表达式删除空间,如下所示:

            var corrected = Regex.Replace(mm.ToString(), @"To: ", "To:");

但由于某种原因,这对我来说没有意义。根据文档 Raw 属性采用 RFC 2822 格式和 base64url 编码的字符串,从我可以发现 RFC 2822 不允许在标头类型之后有空格。任何帮助将不胜感激 :) 此处的参考是从原始解码的两个字符串,一个有效,另一个无效;

//plain text that works:
To:test@test.com
Subject: Test subject
Content-Type: text/html; charset=us-ascii

<h1>Test body <h1>

// mime message that throw error
To: test@test.com
Subject: test message
Date: Date
MIME-Version: 1.0
Content-Type: text/html; charset=us-ascii

<h1>test body</h1>

【问题讨论】:

    标签: c# gmail-api email-headers mimekit base64url


    【解决方案1】:

    正确的解决方案是这样的:

    var mailMessage = new MailMessage
    {
        Subject = "test subject",
        Body = " <h1>test body</h1>"
    };
    mailMessage.IsBodyHtml = true;
    mailMessage.To.Add("testemail");
    
    MimeMessage mm = MimeMessage.CreateFromMailMessage(mailMessage);
    byte[] rawMimeData;
    using (var memory = new MemoryStream ()) {
        mm.WriteTo(memory);
        rawMimeData = memory.ToArray();
    }
    
    var gmailMessage = new Google.Apis.Gmail.v1.Data.Message
    {
        Raw = Base64UrlEncode(rawMimeData)
    };
    
    service.Users.Messages.Send(gmailMessage, "me").execute();
    
    // Encoding method
    public static string Base64UrlEncode(byte[] bytes)
    {
        return Convert.ToBase64String(bytes)
            .Replace('+', '-')
            .Replace('/', '_')
            .Replace("=", "");
    }
    

    【讨论】:

    • 这就像一个魅力。感谢您的宝贵时间
    • 太棒了,很高兴成功了!我还发布了一个新版本的 MimeKit 来解决这个问题:v2.15.1
    【解决方案2】:

    终于解决了!!由于某种原因,MimeMessage 上的 ToString 方法在 mime 消息的字符串表示形式的开头和结尾添加了回车符和换行符 (\r\n),例如 "\r\n-------string--- ------\r\n" 这显然扼杀了 gmail api,所以我只是使用了 trim 方法,就像 mm.ToString().Trim('\r', '\n') 瞧,它完美无缺。不确定它是错误还是预期行为,但Jstedfast 如果您有机会阅读这篇文章,请提供您的反馈。

    【讨论】:

    • 看起来像 2.14 中引入的错误,当时我在调用 ToString() 方法时删除了以X-MimeKit-Warning: Do NOT use ToString()!!! Use WriteTo() instead! 开始消息的代码。
    猜你喜欢
    • 2019-09-21
    • 2019-10-30
    • 2020-08-23
    • 2018-08-14
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 2020-07-07
    • 2021-10-23
    相关资源
    最近更新 更多