MimeMessage 导致 Gmail Apis 中需要收件人地址错误可能是由于 base64url 编码
MimeMessage causing recipient address required error in Gmail Apis possibly due base64url encoding
编辑 1:进一步研究后发现 space 不是罪魁祸首,但可能是 base64url 编码方法。我提取了纯文本和 MIME 消息的 Raw 字符串,并在在线 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 邮件的原始 属性,这将完美无缺。
为了调试问题,我使用在线工具解码了纯文本和 MIME 消息,我注意到的唯一区别是 space 之前的 header 值,如下所示:
// plain text:
To:testemail
//mime message:
To: testemail
注意“收件人:”后的 space。为了证实我的怀疑,我从 mime 消息中删除了 space 并使用在线工具再次对其进行编码,并将编码后的字符串传递给 Raw 属性 并且它可以正常工作。所以想出了一个 hacky 解决方案,并尝试使用正则表达式删除 space,如下所示:
var corrected = Regex.Replace(mm.ToString(), @"To: ", "To:");
但出于某种原因,它不起作用,这对我来说没有意义。根据文档,Raw 属性 采用 RFC 2822 格式和 base64url 编码的字符串,据我所知,RFC 2822 不允许 space 在 header 类型之后。任何帮助将不胜感激 :)
作为参考,这里的两个字符串都是从原始解码的,而其他的则没有;
//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>
终于解决了!!由于某种原因,MimeMessage 上的 ToString 方法在 mime 消息的字符串表示形式的开头和结尾添加了回车符 return 和换行符 (\r\n),例如“\r\n----- --string--------\r\n" 这显然会阻塞 gmail api 所以我只是像这样使用 trim 方法 mm.ToString().Trim('\r', '\n')
瞧,它完美地工作。不确定它是错误还是预期行为,但 Jstedfast 如果您有机会阅读本文 post 请提供您的反馈。
正确的解法应该是这样的:
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("=", "");
}
编辑 1:进一步研究后发现 space 不是罪魁祸首,但可能是 base64url 编码方法。我提取了纯文本和 MIME 消息的 Raw 字符串,并在在线 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 邮件的原始 属性,这将完美无缺。 为了调试问题,我使用在线工具解码了纯文本和 MIME 消息,我注意到的唯一区别是 space 之前的 header 值,如下所示:
// plain text:
To:testemail
//mime message:
To: testemail
注意“收件人:”后的 space。为了证实我的怀疑,我从 mime 消息中删除了 space 并使用在线工具再次对其进行编码,并将编码后的字符串传递给 Raw 属性 并且它可以正常工作。所以想出了一个 hacky 解决方案,并尝试使用正则表达式删除 space,如下所示:
var corrected = Regex.Replace(mm.ToString(), @"To: ", "To:");
但出于某种原因,它不起作用,这对我来说没有意义。根据文档,Raw 属性 采用 RFC 2822 格式和 base64url 编码的字符串,据我所知,RFC 2822 不允许 space 在 header 类型之后。任何帮助将不胜感激 :) 作为参考,这里的两个字符串都是从原始解码的,而其他的则没有;
//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>
终于解决了!!由于某种原因,MimeMessage 上的 ToString 方法在 mime 消息的字符串表示形式的开头和结尾添加了回车符 return 和换行符 (\r\n),例如“\r\n----- --string--------\r\n" 这显然会阻塞 gmail api 所以我只是像这样使用 trim 方法 mm.ToString().Trim('\r', '\n')
瞧,它完美地工作。不确定它是错误还是预期行为,但 Jstedfast 如果您有机会阅读本文 post 请提供您的反馈。
正确的解法应该是这样的:
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("=", "");
}