<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Go語言實戰 - 使用SendCloud群發郵件

      山坡網需要能夠每周給注冊用戶發送一封名為“本周最熱書籍”的郵件,而之前一直使用的騰訊企業郵箱罷工了,提示說發送請求太多太密集。

      一番尋找之后發現了大家口碑不錯的搜狐SendCloud服務,看了看文檔,價格實惠用起來也方便,于是準備使用它做郵件發送服務器。按照文檔的配置一步步走下來發現在發送郵件的時候竟然出錯了,錯誤提示是“unencrypted connection”,奇怪了。

      由于用的是smtp包的PLAIN認證方式,所以打開源代碼看了看(SublimeText3+GoSublime里ctrl+. ctrl+a輸入包名和結構名直接查看源代碼,誰用誰喜歡),發現這里要求使用加密連接,否則就會出上述錯誤。恩,也能理解,畢竟這里明文發送密碼了。關鍵代碼如下。

      auth := smtp.PlainAuth("", Config.Username, Config.Password, Config.Host)
      smtp.SendMail(addr, auth, from, to, []byte(self.String()))

      問題明白之后思路也出來了,自己寫一個不需要加密鏈接的PLAIN認證就好了。這里提一下smtp包的設計,看下面這段代碼。

      // Auth is implemented by an SMTP authentication mechanism.
      type Auth interface {
          // Start begins an authentication with a server.
          // It returns the name of the authentication protocol
          // and optionally data to include in the initial AUTH message
          // sent to the server. It can return proto == "" to indicate
          // that the authentication should be skipped.
          // If it returns a non-nil error, the SMTP client aborts
          // the authentication attempt and closes the connection.
          Start(server *ServerInfo) (proto string, toServer []byte, err error)

          // Next continues the authentication. The server has just sent
          // the fromServer data. If more is true, the server expects a
          // response, which Next should return as toServer; otherwise
          // Next should return toServer == nil.
          // If Next returns a non-nil error, the SMTP client aborts
          // the authentication attempt and closes the connection.
          Next(fromServer []byte, more bool) (toServer []byte, err error)
      }

       

      // SendMail connects to the server at addr, switches to TLS if
      // possible, authenticates with the optional mechanism a if possible,
      // and then sends an email from address from, to addresses to, with
      // message msg.
      func SendMail(addr string, a Auth, from string, to []string, msg []byte) error

      smtp.SendMail的第二個參數是一個Auth接口,用來實現多種認證方式。標準庫中實現了兩種認證方式,PLAIN和CRAMMD5Auth,關于這部分知識大家可以自行參考smtp協議中認證部分的定義。這里就不贅述了。

      搞清楚了原理就動手吧。直接把標準庫中PLAIN的實現拿過來,刪除其中需要加密函數的部分,如下紅字部分。

      type plainAuth struct {
          identity, username, password string
          host                         string
      }


      func UnEncryptedPlainAuth(identity, username, password, host string) Auth {
          return &plainAuth{identity, username, password, host}
      }

      func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
          if !server.TLS {
              advertised := false
              for _, mechanism := range server.Auth {
                  if mechanism == "PLAIN" {
                      advertised = true
                      break
                  }
              }
              if !advertised {
                  return "", nil, errors.New("unencrypted connection")
              }
          }
          if server.Name != a.host {
              return "", nil, errors.New("wrong host name")
          }
          resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password)
          return "PLAIN", resp, nil
      }

      func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, error) {
          return nil, nil
      }

      把發送郵件的代碼改成下面這樣,再試試看。

      auth := UnEncryptedPlainAuth("", Config.Username, Config.Password, Config.Host)
      smtp.SendMail(addr, auth, from, to, []byte(self.String()))

      恩,還是出錯,這次的錯誤變成“unrecognized command”,看來是SendCloud的服務器并不支持這種驗證方式。于是我打開它的文檔,發現smtp使用介紹的頁面有幾種語言的范例代碼,看了看Python的代碼后發現SendCloud應該用的是Login認證。好吧,之前是犯了經驗主義錯誤了。

      再次打開smtp協議的定義,翻到WikiPedia上smtp的(這里標紅是因為wiki上的文檔也是會過期的)LOGIN認證的文檔,上面說,采用LOGIN認證服務器和客戶端應該會產生如下對話,下面S代表服務器,C代表客戶端。

      C:auth login ------------------------------------------------- 進行用戶身份認證
      S:334 VXNlcm5hbWU6 ----------------------------------- BASE64編碼“Username:”
      C:Y29zdGFAYW1heGl0Lm5ldA== ----------------------------------- 用戶名,使用BASE64編碼
      S:334 UGFzc3dvcmQ6 -------------------------------------BASE64編碼"Password:"
      C:MTk4MjIxNA== ----------------------------------------------- 密碼,使用BASE64編碼
      S:235 auth successfully -------------------------------------- 身份認證成功

      看起來挺簡單,照著寫了一個LoginAuth。

      type loginAuth struct {
        username, password string
      }

      func LoginAuth(username, password string) smtp.Auth {
        return &loginAuth{username, password}
      }

      func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
        return "LOGIN", []byte{}, nil
      }

      func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {
        if more {
          switch string(fromServer) {
          case "Username:":
            return []byte(a.username), nil
          case "Password:":
            return []byte(a.password), nil
          }
        }
        return nil, nil
      }

      把發送郵件的代碼改成下面這樣。

      auth := LoginAuth(Config.Username, Config.Password)
      smtp.SendMail(addr, auth, from, to, []byte(self.String()))

      運行,還報錯,這次錯誤信息是 Authentication Failed,認證失敗。這說明Login認證的方式是對的,但登錄失敗了。再三確定賬號和密碼的正確之后我決定用WireShark抓包看看過程。

      V75FH7RLZ0RB$I`[$78{(_W

      注意看,AUTH LOGIN之后來了兩條334 Password,咦?這里不應該是先來Username接著來Password的嗎?為什么是來了兩次Password。難道是LOGIN協議改了?

      為了確認登陸過程,我用SendCloud文檔中Python的代碼跑了一遍,終于發現了不同。原來,在發送AUTH LOGIN之后需要帶上Username。修改LoginAuth的Start函數。

      func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
        return "LOGIN", []byte{}, nil
        return "LOGIN", []byte(a.username), nil
      }

      好了!郵件發送成功!大約花了30分鐘,我從一個完全不懂SMTP協議的人完成了LOGIN協議的補充。感嘆一下Go的簡單,標準庫沒有黑盒子一樣的厚重感,薄的一捅就透,一看就懂。

      posted @ 2013-12-26 15:07  AllenDang  閱讀(4018)  評論(6)    收藏  舉報
      主站蜘蛛池模板: 欧美成人精品手机在线| 国产精品成人一区二区三| 99riav国产精品视频| 女人被狂躁c到高潮喷水一区二区| 国产成本人片无码免费| 婷婷综合久久中文字幕| 日韩有码中文字幕av| 粉嫩av蜜臀一区二区三区| 国语精品自产拍在线观看网站| 少妇被粗大的猛烈进出69影院一 | 国产精品自拍一二三四区| 国产精品中文av专线| 亚洲成aⅴ人在线电影| 丰满人妻熟妇乱又伦精品软件| 亚洲乱色一区二区三区丝袜| 五月婷婷久久草| 在线观看视频一区二区三区| 成人又黄又爽又色的视频| 亚洲免费成人av一区| 亚洲美女av一区二区| 四虎成人精品无码| 国产精品久久久久久久久久妞妞 | 少妇宾馆粉嫩10p| 久久久久无码精品国产AV| 小金县| 中文字幕久久人妻熟人妻| 最新中文乱码字字幕在线| 日韩高清不卡免费一区二区| 免费99视频| 在线精品国精品国产不卡| 人妻丝袜AV中文系列先锋影音| 久久久久久综合网天天| 国产精品无码专区| 欧美高清一区三区在线专区| 国产精品一二三区久久狼| 国产亚洲av嫩草久久| 日韩有码中文在线观看| 精品无码专区久久久水蜜桃| 精品一区二区成人码动漫| 亚洲日本精品一区二区| 国产高清色高清在线观看 |