mirror of https://github.com/veypi/OneAuth.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
2.9 KiB
Go
137 lines
2.9 KiB
Go
//
|
|
// Copyright (C) 2024 veypi <i@veypi.com>
|
|
// 2025-03-04 16:08:06
|
|
// Distributed under terms of the MIT license.
|
|
//
|
|
|
|
package email
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net/smtp"
|
|
|
|
"github.com/veypi/vbase/models"
|
|
)
|
|
|
|
// SMTPProvider SMTP 邮件提供商
|
|
type SMTPProvider struct {
|
|
host string
|
|
port int
|
|
username string
|
|
password string
|
|
from string
|
|
fromName string
|
|
}
|
|
|
|
// NewSMTPProvider 创建 SMTP 提供商
|
|
func NewSMTPProvider() (*SMTPProvider, error) {
|
|
host, err := models.GetSetting(models.SettingEmailSMTPHost)
|
|
if err != nil || host == "" {
|
|
return nil, fmt.Errorf("smtp host not configured")
|
|
}
|
|
|
|
port, _ := models.GetSettingInt(models.SettingEmailSMTPPort)
|
|
if port == 0 {
|
|
port = 587
|
|
}
|
|
|
|
username, _ := models.GetSetting(models.SettingEmailSMTPUser)
|
|
password, _ := models.GetSetting(models.SettingEmailSMTPPass)
|
|
from, _ := models.GetSetting(models.SettingEmailFrom)
|
|
fromName, _ := models.GetSetting(models.SettingEmailFromName)
|
|
|
|
if from == "" {
|
|
from = username
|
|
}
|
|
|
|
return &SMTPProvider{
|
|
host: host,
|
|
port: port,
|
|
username: username,
|
|
password: password,
|
|
from: from,
|
|
fromName: fromName,
|
|
}, nil
|
|
}
|
|
|
|
// Send 发送邮件
|
|
func (p *SMTPProvider) Send(to, subject, content string) error {
|
|
from := p.from
|
|
if p.fromName != "" {
|
|
from = fmt.Sprintf("%s <%s>", p.fromName, p.from)
|
|
}
|
|
|
|
// 构造邮件内容
|
|
msg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n%s",
|
|
from, to, subject, content)
|
|
|
|
addr := fmt.Sprintf("%s:%d", p.host, p.port)
|
|
|
|
// 使用 TLS
|
|
tlsConfig := &tls.Config{
|
|
ServerName: p.host,
|
|
}
|
|
|
|
conn, err := tls.Dial("tcp", addr, tlsConfig)
|
|
if err != nil {
|
|
// 尝试非 TLS
|
|
return smtp.SendMail(addr, smtp.PlainAuth("", p.username, p.password, p.host), p.from, []string{to}, []byte(msg))
|
|
}
|
|
defer conn.Close()
|
|
|
|
client, err := smtp.NewClient(conn, p.host)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer client.Close()
|
|
|
|
// 认证
|
|
auth := smtp.PlainAuth("", p.username, p.password, p.host)
|
|
if err = client.Auth(auth); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 设置发件人
|
|
if err = client.Mail(p.from); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 设置收件人
|
|
if err = client.Rcpt(to); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 写入数据
|
|
w, err := client.Data()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer w.Close()
|
|
|
|
_, err = w.Write([]byte(msg))
|
|
return err
|
|
}
|
|
|
|
// SendVerificationCode 发送验证码邮件
|
|
func SendVerificationCode(to, code string) error {
|
|
provider, err := NewProvider()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
subject := "验证码"
|
|
content := fmt.Sprintf(`
|
|
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
|
<h2>您的验证码</h2>
|
|
<p>您的验证码是:</p>
|
|
<div style="font-size: 32px; font-weight: bold; color: #333; padding: 20px; background: #f5f5f5; text-align: center; letter-spacing: 5px;">
|
|
%s
|
|
</div>
|
|
<p>此验证码 5 分钟内有效,请勿泄露给他人。</p>
|
|
</div>
|
|
`, code)
|
|
|
|
return provider.Send(to, subject, content)
|
|
}
|