c# - 使用 MimeKit、C# Winforms 和 Google API 的 Gmail 草稿(带附件的 HTML)

标签 c# winforms google-api gmail mimekit

我正在尝试使用 C# 在 winforms 应用程序中生成 Gmail 草稿邮件。草稿消息需要采用 HTML 格式并且能够包含附件。

我能够使用 AE.Net.Mail 生成带有附件的草稿,但草稿消息是纯文本形式的(我不知道如何对 AE 进行编码)。 Net.Mail 给我一封 HTML Gmail 草稿邮件)。

为了将消息转换为 HTML 格式,我使用 MimeKit 获取 System.Net.Mail 消息并将其转换为 MimeMessage 消息。但是,我无法弄清楚如何按照 Gmail 草案规范的要求将 MIME 消息放入 RFC 2822 格式和 URL 安全的 base64 编码字符串中。

以下是 MimeKit 转换尝试的代码:

var service = new GmailService(new BaseClientService.Initializer()
{
    HttpClientInitializer = credential,
    ApplicationName = ApplicationName,
});

MailMessage msg = new MailMessage(); //System.Net.Mail
msg.IsBodyHtml = true;
msg.Subject = "HTML Email";
msg.Body = "<a href = 'http://www.yahoo.com/'>Enjoy Yahoo!</a>";
msg.Attachments.Add(file);

MimeMessage message = MimeMessage.CreateFromMailMessage(msg); //MimeKit conversion

//At this point I cannot figure out how to get the MIME message into 
//an RFC 2822 formatted and URL-safe base64 encoded string
//as required by the Gmail draft specification
//See working code below for how this works in AE.Net.Mail

下面是使用 AE.Net.Mail 的代码,该代码可以运行,但会以纯文本形式生成 Gmail 草稿正文(基于 Jason Pettys 的 this article) ):

 var service = new GmailService(new BaseClientService.Initializer()
 {
     HttpClientInitializer = credential,
     ApplicationName = ApplicationName,
 });

 var msg = new AE.Net.Mail.MailMessage //msg created in plain text not HTML format
 {
     Body = "<a href = 'http://www.yahoo.com/'>Enjoy Yahoo!</a>"
 };

 var bytes = System.IO.File.ReadAllBytes(filePath);
 AE.Net.Mail.Attachment file = new AE.Net.Mail.Attachment(bytes, @"application/pdf", FileName, true);
 msg.Attachments.Add(file);

 var msgStr = new StringWriter();
 msg.Save(msgStr);
 Message m = new Message();
 m.Raw = Base64UrlEncode(msgStr.ToString());

 Draft draft = new Draft(); //Gmail draft
 draft.Message = m;

 service.Users.Drafts.Create(draft, "me").Execute();

 private static string Base64UrlEncode(string input)
 {
     var inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
     // Special "url-safe" base64 encode.
     return Convert.ToBase64String(inputBytes)
       .Replace('+', '-')
       .Replace('/', '_')
       .Replace("=", "");
 }

有没有办法将 MimeKit 的 MimeMessage 消息转换为 RFC 2822 格式和 URL 安全的 base64 编码字符串,以便可以将其生成为 Gmail 草稿?如果做不到这一点,有没有办法在编码之前以 HTML 格式创建 AE.Net.Mail 消息?非常感谢所有帮助。

最佳答案

做你想做的事情的最简单方法是这样的:

static string Base64UrlEncode (MimeMessage message)
{
    using (var stream = new MemoryStream ()) {
        message.WriteTo (stream);

        return Convert.ToBase64String (stream.GetBuffer (), 0, (int) stream.Length)
            .Replace ('+', '-')
            .Replace ('/', '_')
            .Replace ("=", "");
    }
}

但是更有效的方法需要实现我们自己的 UrlEncoderFilter 来替换您的“.Replace (...)”逻辑:

using MimeKit;
using MimeKit.IO;
using MimeKit.IO.Filters;

// ...

class UrlEncodeFilter : IMimeFilter
{
    byte[] output = new byte[8192];

    #region IMimeFilter implementation
    public byte[] Filter (byte[] input, int startIndex, int length, out int outputIndex, out int outputLength)
    {
        if (output.Length < input.Length)
            Array.Resize (ref output, input.Length);

        int endIndex = startIndex + length;

        outputLength = 0;
        outputIndex = 0;

        for (int index = startIndex; index < endIndex; index++) {
            switch ((char) input[index]) {
            case '\r': case '\n': case '=': break;
            case '+': output[outputLength++] = (byte) '-'; break;
            case '/': output[outputLength++] = (byte) '_'; break;
            default: output[outputLength++] = input[index]; break;
            }
        }

        return output;
    }

    public byte[] Flush (byte[] input, int startIndex, int length, out int outputIndex, out int outputLength)
    {
        return Filter (input, startIndex, length, out outputIndex, out outputLength);
    }

    public void Reset ()
    {
    }
    #endregion
}

使用它的方式如下:

static string Base64UrlEncode (MimeMessage message)
{
    using (var stream = new MemoryStream ()) {
        using (var filtered = new FilteredStream (stream)) {
            filtered.Add (EncoderFilter.Create (ContentEncoding.Base64));
            filtered.Add (new UrlEncodeFilter ());

            message.WriteTo (filtered);
            filtered.Flush ();
        }

        return Encoding.ASCII.GetString (stream.GetBuffer (), 0, (int) stream.Length);
    }
}

关于c# - 使用 MimeKit、C# Winforms 和 Google API 的 Gmail 草稿(带附件的 HTML),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35655019/

相关文章:

javascript - 通过 Ajax 加载 Google 可视化

php - 从 AdExchange 卖家 API 生成报告时添加 `alt` 参数

c# - 如何将 int 格式化为带有前导零和逗号的字符串

c# - 如何模拟单元测试的 Elasticsearch NEST GetMapping 响应

c# - WinForms 多线程 : Execute a GUI update only if the previous one has finished

c# - 设计表单以在 Windows CE 上处理不同的分辨率和宽高比

c# - 具有可空类型的 REST?

c# - 通过其他应用程序的窗口设置wpf窗口的所有者,可以吗?

c# - 选择时 TreeView 所有者绘制故障

javascript - 右侧的谷歌地图信息窗口位置