首次提交:初始化项目代码
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
package email
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"time"
|
||||
|
||||
"cloudnest/internal/config"
|
||||
"cloudnest/internal/infrastructure/database"
|
||||
"cloudnest/internal/pkg/logger"
|
||||
)
|
||||
|
||||
// EmailService provides email sending and verification code management.
|
||||
// EmailService 提供邮件发送和验证码管理功能。
|
||||
type EmailService struct {
|
||||
cfg *config.EmailConfig
|
||||
redis *database.RedisClient
|
||||
}
|
||||
|
||||
// NewEmailService creates a new EmailService.
|
||||
// NewEmailService 创建一个新的 EmailService。
|
||||
func NewEmailService(cfg *config.EmailConfig, redis *database.RedisClient) *EmailService {
|
||||
return &EmailService{cfg: cfg, redis: redis}
|
||||
}
|
||||
|
||||
// SendVerifyCode generates a 6-digit verification code, sends it via email, and stores it in Redis.
|
||||
// SendVerifyCode 生成6位数字验证码,通过邮件发送,并存入 Redis。
|
||||
//
|
||||
// Returns:
|
||||
// - code: The generated verification code.
|
||||
// - err: Any error that occurred.
|
||||
func (s *EmailService) SendVerifyCode(toEmail string) (code string, err error) {
|
||||
if s.cfg.SMTPUsername == "" {
|
||||
return "", fmt.Errorf("邮件服务未配置")
|
||||
}
|
||||
|
||||
code = generateCode(6)
|
||||
subject := "CloudNest 邮箱验证码"
|
||||
body := fmt.Sprintf("您的验证码是:%s,有效期10分钟,请勿泄露给他人。", code)
|
||||
|
||||
if err = s.sendMail(toEmail, subject, body); err != nil {
|
||||
logger.Error("failed to send email", "error", err, "to", toEmail)
|
||||
return "", err
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
key := fmt.Sprintf("email_code:%s", toEmail)
|
||||
if err = s.redis.Client.Set(ctx, key, code, 10*time.Minute).Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
||||
// VerifyCode checks the email verification code and deletes it from Redis on success.
|
||||
// VerifyCode 检查邮箱验证码,成功时从 Redis 中删除。
|
||||
func (s *EmailService) VerifyCode(email, code string) bool {
|
||||
ctx := context.Background()
|
||||
key := fmt.Sprintf("email_code:%s", email)
|
||||
val, err := s.redis.Client.Get(ctx, key).Result()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if val != code {
|
||||
return false
|
||||
}
|
||||
s.redis.Client.Del(ctx, key)
|
||||
return true
|
||||
}
|
||||
|
||||
func generateCode(length int) string {
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = byte(rand.Intn(10)) + '0'
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (s *EmailService) sendMail(to, subject, body string) error {
|
||||
from := s.cfg.SMTPUsername
|
||||
addr := fmt.Sprintf("%s:%d", s.cfg.SMTPHost, s.cfg.SMTPPort)
|
||||
|
||||
msg := []byte(fmt.Sprintf("To: %s\r\nFrom: %s <%s>\r\nSubject: %s\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n%s",
|
||||
to, s.cfg.FromName, from, subject, body))
|
||||
|
||||
if s.cfg.SMTPPort == 587 {
|
||||
return sendMailSTARTTLS(addr, s.cfg.SMTPHost, from, s.cfg.SMTPPassword, []string{to}, msg)
|
||||
}
|
||||
|
||||
auth := smtp.PlainAuth("", from, s.cfg.SMTPPassword, s.cfg.SMTPHost)
|
||||
return smtp.SendMail(addr, auth, from, []string{to}, msg)
|
||||
}
|
||||
|
||||
func sendMailSTARTTLS(addr, host, from, password string, to []string, msg []byte) error {
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client, err := smtp.NewClient(conn, host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
tlsConfig := &tls.Config{ServerName: host}
|
||||
if err := client.StartTLS(tlsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
auth := smtp.PlainAuth("", from, password, host)
|
||||
if err := client.Auth(auth); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := client.Mail(from); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, addr := range to {
|
||||
if err := client.Rcpt(addr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
w, err := client.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return client.Quit()
|
||||
}
|
||||
Reference in New Issue
Block a user