Thursday, August 2, 2012

[C#] Using SmtpClient sent email with response via Gmail

最近用Sikuli做了個UI Test,要把結果用email的方式丟出來,找了一下,原本打算做模組化一點,各個不同的測試從Sikuli回傳給Python然後再去處理寄信的問題,後來討論了一下,多花力氣去維護一個語言不太划算(雖然我想玩Python啊),所以決定自己寫個頁面去做寄信的事。

找了一下,.NET有這個SmtpClient 類別可以來寄信,而且sample code也蠻詳細的,所以就來試一下了。

我是直接用需要帳號密碼登入才能用的gmail來寄,一開始的code是長這樣
    private const string Username = "username"; //update your gmail acc/pw here
    private const string Passowrd = "passowrd";

    private string MailBody {
        get
        {
            return string.IsNullOrEmpty(Request.QueryString["result"])
                       ? string.Empty
                       : Request.QueryString["result"];
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        if (MailBody == string.Empty) return;

        using(var smtpServer = new SmtpClient("smtp.gmail.com", 587)
                             {
                                 EnableSsl = true,
                                 Timeout = 10000,
                                 DeliveryMethod = SmtpDeliveryMethod.Network,
                                 Credentials = new NetworkCredential(Username, Passowrd)
                             })
        {
            smtpServer.Send(new MailMessage("[email protected]", "[email protected]", "test", MailBody)
                                {
                                    BodyEncoding = Encoding.UTF8,
                                    DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure
                                });
        }
   }

其實這樣就可以寄了,但是拿不到成功或失敗的訊息,所以後來又加了SmtpClient.SendCompleted Event來去抓回應,這邊除了加上SendCompleted Event,寄信時原本是用.Send也要改成SendAsync,然後因為改成非同步模式,所以如果你在webpage上做的話,必須在 .aspx 的 <%@ Page %> 內加上 Async="true" ,不然會有錯誤訊息的。

原本以為這樣就可以拉到寄信的結果,結果我發現一直都是回應 Cancelled ,研究了很久,最後發現因為前面是使用 using 去叫 SmtpClient ,所以他事情做完就自動去 Dispose(),但是現在改用非同步模式去寄信,所以一Send SmtpClient 就被清掉,自然是不會有結果的(我猜他Dispose()時有可能自動做了SendAsyncCancel()還是因為物件不見就怎樣的關係),最後我改了寫法,長的像下面這樣。

    private const string Username = "username"; //update your gmail acc/pw here
    private const string Passowrd = "passowrd";

    private string MailBody {
        get
        {
            return string.IsNullOrEmpty(Request.QueryString["result"])
                       ? string.Empty
                       : Request.QueryString["result"];
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        if (MailBody == string.Empty) return;

        var smtpServer = new SmtpClient("smtp.gmail.com", 587)
                             {
                                 EnableSsl = true,
                                 Timeout = 10000,
                                 DeliveryMethod = SmtpDeliveryMethod.Network,
                                 Credentials = new NetworkCredential(Username, Passowrd)
                             };

        var message = new MailMessage("[email protected]", "[email protected]", "test", MailBody)
                          {
                              BodyEncoding = Encoding.UTF8,
                              DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure
                          };

        smtpServer.SendCompleted += SendCompletedCallback;
        try
        {
            smtpServer.SendAsync(message, "token");
        }
        catch (Exception ex)
        {
            Label1.Text = ex.Message;
        }
    }

    private void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
    {
        // Get the unique identifier for this asynchronous operation.
        var token = (string)e.UserState;

        if (e.Cancelled)
        {
            Label1.Text = String.Format("[{0}] Send canceled.", token);
            return;
        }
        Label1.Text = e.Error != null ? String.Format("[{0}] {1}", token, e.Error) : String.Format("Message [{0}] sent.", token);
    }

使用SendAsync寄的時候,因為非同步的關係,所以會多要你傳一個token來辨識這是哪封信的結果,這在寄多封信的時候很有用,我這邊只寄一封信我就不理他了,詳情可以參閱SmtpClient.SendAsync 方法 (MailMessage, Object)

基本上這樣就可以成功的用Gmail去幫你寄信了,這在自己做測試或監控,需要小量寄信的時候很方便,當然這段程式再延展起來也是可以拿來寄電子報、會員信之類的,就看你怎麼發揮了。

SmtpClient

最後附上寄成功的信件內容,收工。

歐對了,我這個頁面的需求是會把QueryString "result"的內容寄出去,所以會多一小段東西,不然會更簡潔一點。

2 comments:

  1. Paris Fashion Week would Replica handbags uk have been incomplete without replica Yves Saint Laurent bags Anthony Vaccarello’s homage to maison founder Yves Saint Laurent in the Saint Laurent spring/summer 2019 collection.

    ReplyDelete
  2. Best cheap Soccer Jerseys Shirts Wholesale Shop for Custom Team Soccer Jerseys Online,cheap xherdan shaqiri JerseysFCB Jerseys,cheap Euro 2020 Kit Top.

    ReplyDelete

Related Posts Plugin for WordPress, Blogger...