2

我正在尝试使用 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的这篇文章):

 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 草稿?AE.Net.Mail如果做不到这一点,有没有办法在编码之前以 HTML 格式创建消息?非常感谢所有帮助。

4

3 回答 3

2

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

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);
    }
}
于 2016-02-27T01:03:28.567 回答
2

这是我用来创建带有附件的 gmail 草稿的 C# 代码...

using System;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Gmail.v1;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System.IO;
using System.Threading;
using System.Net.Mail;

namespace SendStatusReportsAddin1
{
    class Program
    {
        // If modifying these scopes, delete your previously saved credentials
        // at ~/.credentials/gmail-dotnet-quickstart.json
        //static string[] Scopes = { GmailService.Scope.GmailReadonly };
        static string[] Scopes = { GmailService.Scope.MailGoogleCom };
        static string ApplicationName = "Gmail API .NET Quickstart";

        static void Main(string[] args)
        {
            //Authorization
              UserCredential credential;

              using (var stream =
                  new FileStream("client_secret2.json", FileMode.Open, FileAccess.Read))
              {
                  string credPath = System.Environment.GetFolderPath(
                      System.Environment.SpecialFolder.Personal);
                  credPath = Path.Combine(credPath, ".credentials3/gmail-dotnet.json");

                  credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                      GoogleClientSecrets.Load(stream).Secrets,
                      Scopes,
                      "user",
                      CancellationToken.None,
                      new FileDataStore(credPath, true)).Result;
                  Console.WriteLine("Credential file saved to: " + credPath);
              }

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

            //Create mail message
              MailMessage mailmsg = new MailMessage();
              {
                  mailmsg.Subject = "My test subject";
                  mailmsg.Body = "<b>My smart message </b>";
                  mailmsg.From = new MailAddress("joe.blow@hotmail.com");
                  mailmsg.To.Add(new MailAddress("jeff.jones@gmail.com"));
                  mailmsg.IsBodyHtml = true;
              }

            //add attachment
              string statusreportfile =
                        @"C:\Users\ey96a\Google Drive\10 Status-Vacation-Expense\Status Reports\UUM RewriteStatus Report.pdf";

              Attachment data = new Attachment(statusreportfile);
              mailmsg.Attachments.Add(data);

            //Make mail message a Mime message
              MimeKit.MimeMessage mimemessage = MimeKit.MimeMessage.CreateFromMailMessage(mailmsg);

            //Use Base64URLEncode to encode the Mime message
              Google.Apis.Gmail.v1.Data.Message finalmessage = new Google.Apis.Gmail.v1.Data.Message();
              finalmessage.Raw = Base64UrlEncode(mimemessage.ToString());

            //Create the draft email
              var mydraft = new Google.Apis.Gmail.v1.Data.Draft();
              mydraft.Message = finalmessage;

              var resultdraft = service.Users.Drafts.Create(mydraft, "me").Execute();

            //Send the email (instead of creating a draft)
              var resultsend = service.Users.Messages.Send(finalmessage, "me").Execute();

            //Open the SendStatusReports form
              aOpenForm.myForm1();

        }  //end of Main

        //Base64 URL encode
        public static string Base64UrlEncode(string input)
        {
            var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
            // Special "url-safe" base64 encode.

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

    } //end of class Program

}
于 2017-04-30T00:56:53.713 回答
0

如果做不到这一点,有没有办法在编码之前以 HTML 格式创建 AE.Net.Mail 消息?

你可以试试

msg.ContentType = "text/html"; 

在您的 AE.Net.Mail.MailMessage

于 2016-03-01T16:38:15.283 回答