之前不知道怎么发邮件的功能,记录一下

总体的功能实现是:要改密码,绑定/解绑邮箱的时候,我们就会给邮箱发信息确认。

1
go get gopkg.in/mail.v2

==config.go==

1
2
3
4
5
email:
address: xxxxxxx
smtpHost: smtp.qq.com
smtpEmail: xxxx@qq.com
smtpPass: xxxxx

==email.go==

发送的实现其实并不是服务器内部决定的,而是通过QQ邮箱,相当于是将QQ邮箱当作代理,让QQ邮箱来帮我们发送邮件。

那么想要让QQ邮箱为我们发送代理,我们就需要QQ邮箱的权限,因此我们要想取开通一下权限

  1. 设置我们发送的邮箱类型(还可以选择其他邮箱)smtpHost
  2. 去网页里面开启权限,获得smtpPass,这个相当于权限的钥匙
  3. 我们要确认发送方的地址 SmtpEmailFrom
  4. 我们还要确认发送方的 姓名 subject
  5. 我们还需要设置一下给谁发邮箱,一般来说这个谁 需要 用户自己输入或者数据库读取 To
  6. 开始写信封,确认一下信的内容形式
  7. 发送即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package email

import (
conf "gin-mall/conf/sql"
"gin-mall/consts"
"gopkg.in/mail.v2"
)

type EmailSender struct {
SmtpHost string `json:"smtp_host"`
SmtpEmailFrom string `json:"smtp_email_from"`
SmtpPass string `json:"smtp_pass"`
}

func NewEmailSender() *EmailSender {
eConfig := conf.Config.Email
return &EmailSender{
SmtpHost: eConfig.SmtpHost,
SmtpEmailFrom: eConfig.SmtpEmail,
SmtpPass: eConfig.SmtpPass,
}
}

func (s *EmailSender) Send(data, emailTo, subject string) error {
m := mail.NewMessage()
m.SetHeader("From", s.SmtpEmailFrom) //SmtpEmailFrom is the email address of the sender
m.SetHeader("To", emailTo) // emailTo is the email address of the recipient
m.SetHeader("Subject", subject) // subject is the subject of the email
m.SetBody("text/html", data) // data is the body of the email
d := mail.NewDialer(s.SmtpHost, consts.SmtpEmailPort, s.SmtpEmailFrom, s.SmtpPass)
d.StartTLSPolicy = mail.MandatoryStartTLS
if err := d.DialAndSend(m); err != nil {
return err
}
return nil // return nil if the email is sent successfully
}

为了确认安全,所以我们还要再加一个token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func GenerateEmailToken(uid uint, email, password string, operationType uint) (token string, err error) {
claims := EmailClaims{
ID: uid,
Email: email,
Password: password,
OperationType: operationType,
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(10 * time.Minute).Unix(),
Issuer: "cmall",
},
}
token, err = jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(jwtSecret))
return token, err
}

func ParseEmailToken(token string) (*EmailClaims, error) {
tokenClaims, err := jwt.ParseWithClaims(token, &EmailClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(jwtSecret), nil
})
if tokenClaims != nil {
if claims, ok := tokenClaims.Claims.(*EmailClaims); ok && tokenClaims.Valid {
return claims, nil
}
}
return nil, err
}

最后业务处理

  1. 发送邮件
  2. 收到邮件解密
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
func (s *UserSrv) SendEmail(ctx context.Context, req *types.SendEmailServiceReq) (resp interface{}, err error) {
u, err := ctl.GetUserInfo(ctx)
if err != nil {
log.LogrusObj.Error(err)
return
}

var address string
token, err := jwt.GenerateEmailToken(u.Id, req.Email, req.Password, req.OperationType)
if err != nil {
log.LogrusObj.Error(err)
return nil, err
}

sender := email.NewEmailSender()
address = conf.Config.Email.ValidEmail + token
mailText := fmt.Sprintf(consts.EmailOperationMap[req.OperationType], address)
if err = sender.Send(mailText, req.Email, consts.EmailSubject); err != nil {
log.LogrusObj.Error(err)
return
}

return
}

func (s *UserSrv) ValidEmail(ctx context.Context, req *types.ValidEmailReq) (resp interface{}, err error) {
var uId uint
var eml string
var pass string
var OperationType uint

if req.Token == "" {
err = errors.New("token不存在")
return
}

claims, err := jwt.ParseEmailToken(req.Token)
if err != nil {
return
} else {
uId = claims.ID
eml = claims.Email
pass = claims.Password
OperationType = claims.OperationType
}

userDao := dao.NewUserDao(ctx)
user, err := userDao.GetUserById(uId)
if err != nil {
return
}

switch OperationType {
case consts.EmailOperationBinding:
user.Email = eml
case consts.EmailOperationNoBinding:
user.Email = ""
case consts.EmailOperationUpdatePassword:
err = user.SetPassword(pass)
if err != nil {
log.LogrusObj.Error("密码加密错误")
return
}
default:
return nil, errors.New("操作类型错误")
}

err = userDao.UpdateUserById(uId, user)
if err != nil {
log.LogrusObj.Error(err)
return
}

resp = &types.UserInfoResp{
ID: user.ID,
UserName: user.UserName,
NickName: user.NickName,
Email: user.Email,
Status: user.Status,
Avatar: user.AvatarURL(),
CreateAt: user.CreatedAt.Unix(),
}

return

}

总结

这个东西,写了一遍就知道怎么写了

不过还是要看文档…………..