[Csharp]寄送Gmail使用OAuth2

這是一個desktop application桌面應用程式,主要功能利用Gmail寄送郵件。

首先查看Google文件說明,並使用其範例做修改。

1.開啟Gmail API功能

  1. 使用這個連結 在 Google Developers Console建立一個專案並啟用API, 按繼續,來到憑證頁面
  2. 在增加憑證到您的專案頁面,按取消按鈕。
  3. 在頁面頂部,選擇OAuth同意畫面tab。 選擇一個電子郵件地址,輸入一個產品名稱(如果尚未設置),然後單擊儲存按鈕。
  4. 選擇憑證tab,按下建立憑證按鈕,選擇OAuth用戶端ID
  5. 選擇其它,並輸入一個名稱識別,按下建立按鈕。
  6. 建立完成會顯示您的用戶端ID及用戶端密鑰等資訊,按下確定按鈕。
  7. 按下”下載JSON“圖示,把檔案拉至專案Properties目錄,並設定複制到輸出目錄:一律複製

2.建立一個專案,並利用NuGet封裝管理員(工具->NuGet封裝管理員)來增加參考Google.Apis.Gmail.v1。

3.把文件裡的Example copy到Program.cs取代

using Google.Apis.Auth.OAuth2;
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace GmailQuickstart
{
    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 ApplicationName = "Gmail API .NET Quickstart";

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

            using (var stream =
                new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
            {
                string credPath = System.Environment.GetFolderPath(
                    System.Environment.SpecialFolder.Personal);
                credPath = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart.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,
                });

            // Define parameters of request.
            UsersResource.LabelsResource.ListRequest request = service.Users.Labels.List("me");

            // List labels.
            IList<Label> labels= request.Execute().Labels;
            Console.WriteLine("Labels:");
            if (labels != null && labels.Count > 0)
            {
                foreach (var labelItem in labels)
                {
                    Console.WriteLine("{0}", labelItem.Name);
                }
            }
            else
            {
                Console.WriteLine("No labels found.");
            }
            Console.Read();

        }
    }
}

4.執行看看,可以取得所有Label項目。

修改後的後可以寄信及附檔的原始檔如下:

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

namespace GMailSender
{

    class Program
    {
        // If modifying these scopes, delete your previously saved credentials
        // at ~/.credentials/gmail-dotnet-quickstart.json
        static string[] Scopes = { GmailService.Scope.GmailSend };//GmailService.Scope.GmailReadonly
        static string ApplicationName = "Gmail Sender";
        private static readonly ILog logger = LogManager.GetLogger(typeof(Program));
        static void Main(string[] args)
        {
            logger.Debug("args.length:" + args.Length);
            if (args.Length != 2 && args.Length < 5)
            {
                Console.WriteLine("參數(均為必輸):\r\n GMailSender.exe 寄件者 標題 內文 收件者 附件");
                return;
            }
            
            if (args[1] == "init" || args.Length >= 5)
            {

                UserCredential credential;

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

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

                // Create Gmail API service.
                var service = new GmailService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = ApplicationName,
                });
                logger.Info("GMailSender.exe " +args[0] +";"+ args[1] + ";" + args[2] + ";" + args[3] + ";" + args[4] );
                if (args.Length >= 5)
                {
                    
                    
                    try
                    {
                        var msg = new AE.Net.Mail.MailMessage
                        {
                            Subject = "=?utf8?B?"+Program.Base64UrlEncode(args[1])+ "?=",
                            Body = args[2],
                            From = new MailAddress(args[0])
                        };
                        //msg.ReplyTo = new MailAddress(args[0]);
                       // msg.Encoding = System.Text.Encoding.GetEncoding("Utf8");
                       // msg.Encoding = Base64UrlEncode.
                        String attachmentFilename = args[4];
                        if (!File.Exists(attachmentFilename))
                        {
                            logger.Info("附加檔案不存在:" + attachmentFilename);
                            Console.WriteLine("附加檔案不存在:" + attachmentFilename);
                            return;
                        }
                        if (attachmentFilename != null && attachmentFilename != String.Empty)
                        {
                            AE.Net.Mail.Attachment attachment = new AE.Net.Mail.Attachment(File.ReadAllBytes(attachmentFilename), DispositionTypeNames.Attachment, Path.GetFileName(attachmentFilename), true);
                           
                            msg.Attachments.Add(attachment);
                        }

                        msg.To.Add(new MailAddress(args[3]));
                        msg.ReplyTo.Add(msg.From); // Bounces without this!!
                        var msgStr = new StringWriter();
                        msg.Save(msgStr);

                        var newMsg = new Google.Apis.Gmail.v1.Data.Message();
                        newMsg.Raw = Program.Base64UrlEncode(msgStr.ToString());
                        service.Users.Messages.Send(newMsg, "me").Execute();
                    }
                    catch (Exception e)
                    {
                        logger.Info("寄送時發生錯誤:", e);
                        Console.Write(e.Message);
                        return;
                    }
                    logger.Info("寄件成功!");
                    
                }
            }
            // Console.Read();

        }
        public static string Base64UrlEncode(string input)
        {
            var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
            return Convert.ToBase64String(inputBytes).Replace("+", "-").Replace("/", "_").Replace("=", "");
        }
    }
}

參考資料:

One thought to “[Csharp]寄送Gmail使用OAuth2”

  1. 謝謝你的分享,有一點要建議的事,subject部分不要使用Base64UrlEncode,因為它是考量safe url code,因此移除了一些字元,你可以用”使用者心得”這幾個字寄信測試看看,會發現收到的信件主旨是亂碼,subject轉碼部分用底下function即可
    public static string Base64UrlEncode(string input)
    {
    var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
    return Convert.ToBase64String(inputBytes);
    }

發表迴響