後臺提供郵件發送驗證碼服務

需求

  1. 我的博客需要增加登錄驗證碼,想通過郵件發送驗證碼
  2. 希望提供一個http服務,其他服務和編程語言不必再寫一個發郵件的方法

實現

package main

import (
	"encoding/base64"
	"errors"
	"net"
	"net/http"
	"strconv"
	"time"
)

func main() {
	http.HandleFunc("/Captcha", Captcha)
	http.ListenAndServe("localhost:8080", nil)
}

func Captcha(w http.ResponseWriter, r *http.Request) {
	code := r.FormValue("code")
	if code == "" {
		w.Write([]byte("false"))
		return
	}
	err := sendCaptcha(code, "smtp.qq.com:25", "[email protected]", "郵箱授權碼,不是登錄密碼", "[email protected]", "[email protected]")
	if err == nil {
		w.Write([]byte("true"))
		return
	}
	w.Write([]byte(err.Error()))
}

func sendCaptcha(code, addr, user, pass, form, to string) error {
	c, err := net.Dial("tcp", addr)
	if err != nil {
		return err
	}
	defer c.Close()

	buf := make([]byte, 256)
	n, err := c.Read(buf)
	if err != nil {
		return err
	}

	_, err = c.Write([]byte("EHLO " + strconv.FormatInt(time.Now().Unix(), 10) + "\r\n"))
	if err != nil {
		return err
	}
	n, err = c.Read(buf)
	if err != nil {
		return err
	}

	_, err = c.Write([]byte("AUTH LOGIN\r\n"))
	if err != nil {
		return err
	}
	n, err = c.Read(buf)
	if err != nil {
		return err
	}

	tmp := base64.StdEncoding.EncodeToString([]byte(user))
	_, err = c.Write([]byte(tmp + "\r\n"))
	if err != nil {
		return err
	}
	n, err = c.Read(buf)
	if err != nil {
		return err
	}

	tmp = base64.StdEncoding.EncodeToString([]byte(pass))
	_, err = c.Write([]byte(tmp + "\r\n"))
	if err != nil {
		return err
	}
	n, err = c.Read(buf)
	if err != nil {
		return err
	}

	_, err = c.Write([]byte("MAIL FROM:<" + form + ">\r\n"))
	if err != nil {
		return err
	}
	n, err = c.Read(buf)
	if err != nil {
		return err
	}

	_, err = c.Write([]byte("RCPT TO:<" + to + ">\r\n"))
	if err != nil {
		return err
	}
	n, err = c.Read(buf)
	if err != nil {
		return err
	}

	_, err = c.Write([]byte("DATA\r\n"))
	if err != nil {
		return err
	}
	n, err = c.Read(buf)
	if err != nil {
		return err
	}

	_, err = c.Write([]byte("from:" + form + "\nto:" + to + "\nsubject:Captcha\nMIMI-Version:1.0\r\n" +
		"Content-Type: multipart/mixed; boundary=\"#BOUNDARY#\"\r\n\r\n" +
		"Content-Transfer-Encoding:7bit\r\n\r\n" +
		"--#BOUNDARY#\r\n" +
		"Content-Type: text/plain; charset=utf-8\r\n" +
		"Content-Transfer-Encoding: printable\r\n\r\n"))
	if err != nil {
		return err
	}

	_, err = c.Write([]byte(code))
	if err != nil {
		return err
	}

	_, err = c.Write([]byte("\r\n--#BOUNDARY#\r\n\r\n--#BOUNDARY#--\r\n.\r\nQUIT\r\n"))
	if err != nil {
		return err
	}
	n, err = c.Read(buf)
	if err != nil {
		return err
	}
	if buf[0] == '2' && buf[1] == '5' && buf[2] == '0' {
		return nil
	}
	return errors.New(string(buf[:n]))
}

用法

  1. 編譯運行上述go代碼
  2. 測試一下curl http://127.0.0.1:8080/Captcha?code=321

總結

  1. 之所以沒有使用go自帶的smtp是因爲新版本go需要用tls連接,當然網上一大堆方案,但是我這裏只是實現簡單的發送郵件驗證碼而已,沒必要搞那麼複雜
  2. 我的這個服務是不會對外提供的,只是提供localhost的服務,這樣比較安全,當然有需要的可以自己改
  3. 這樣我的後臺服務就能通過簡單http get發送一個驗證碼郵件
  4. 特別注意的是現在郵箱的smtp密碼都是授權碼,不是登錄的密碼了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章