fix(邮件发送): 适配 MailerSend SMTP 并迁移基础设施至 1Panel
Motivation: 将通知服务部署到 1Panel 生产环境,集成 MailerSend 邮件服务,修复 SMTP 协议中 MAIL FROM 命令因携带显示名而导致的发送失败问题。 Changes: * 修复 SMTP MAIL FROM 命令传入带显示名的完整地址导致发送失败的问题,新增 extractEmailAddr 提取裸地址 * 更新 SMTP 配置为 MailerSend 真实凭证,From 地址适配其域名验证要求 * 移除 docker-compose 中内置的 MySQL/Redis 服务,改为依赖外部 1Panel 基础设施 * 更新环境变量为生产环境实际凭据
This commit is contained in:
+5
-4
@@ -6,7 +6,7 @@ database:
|
|||||||
host: "mysql"
|
host: "mysql"
|
||||||
port: 3306
|
port: 3306
|
||||||
user: "root"
|
user: "root"
|
||||||
password: "${DB_PASSWORD:-7Qay8mksnwrCffGi}"
|
password: "${DB_PASSWORD:-notify}"
|
||||||
database: "notification"
|
database: "notification"
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
@@ -16,11 +16,12 @@ redis:
|
|||||||
db: 0
|
db: 0
|
||||||
|
|
||||||
smtp:
|
smtp:
|
||||||
host: "smtp.example.com"
|
host: "smtp.mailersend.net"
|
||||||
port: 587
|
port: 587
|
||||||
user: "notify@example.com"
|
user: "MS_hqXDZ6@516886.xyz"
|
||||||
password: "${SMTP_PASSWORD:-}"
|
password: "${SMTP_PASSWORD:-}"
|
||||||
from: "Notification Service <notify@example.com>"
|
# MailerSend 要求 from 域名已验证;未验证 516886.xyz 前先用试用域名
|
||||||
|
from: "Notification Service <MS_hqXDZ6@516886.xyz>"
|
||||||
|
|
||||||
rate_limit:
|
rate_limit:
|
||||||
default: 100
|
default: 100
|
||||||
|
|||||||
+2
-43
@@ -1,58 +1,17 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mysql:
|
|
||||||
image: mysql:8.0
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: rootpass
|
|
||||||
MYSQL_DATABASE: notification
|
|
||||||
MYSQL_USER: notify
|
|
||||||
MYSQL_PASSWORD: notify
|
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
volumes:
|
|
||||||
- mysql_data:/var/lib/mysql
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 3s
|
|
||||||
retries: 10
|
|
||||||
networks:
|
|
||||||
- 1panel-network
|
|
||||||
|
|
||||||
redis:
|
|
||||||
image: redis:7-alpine
|
|
||||||
ports:
|
|
||||||
- "6379:6379"
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 3s
|
|
||||||
retries: 5
|
|
||||||
networks:
|
|
||||||
- 1panel-network
|
|
||||||
|
|
||||||
api:
|
api:
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
environment:
|
environment:
|
||||||
- DB_PASSWORD=notify
|
- SMTP_PASSWORD=mssp.92QdSYS.3z0vklo982xl7qrx.tSlSpXs
|
||||||
- SMTP_PASSWORD=
|
- DB_PASSWORD=7Qay8mksnwrCffGi
|
||||||
- NOTIFY_DATABASE_HOST=mysql
|
|
||||||
- NOTIFY_REDIS_HOST=redis
|
|
||||||
depends_on:
|
|
||||||
mysql:
|
|
||||||
condition: service_healthy
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
- 1panel-network
|
- 1panel-network
|
||||||
|
|
||||||
volumes:
|
|
||||||
mysql_data:
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
1panel-network:
|
1panel-network:
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ func (s *EmailSender) authAndSend(client *smtp.Client, to []string, msg []byte)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := client.Mail(s.cfg.From); err != nil {
|
// MAIL FROM must be a bare address; display names like "Name <a@b.c>" are invalid here.
|
||||||
|
fromAddr := extractEmailAddr(s.cfg.From)
|
||||||
|
if err := client.Mail(fromAddr); err != nil {
|
||||||
return fmt.Errorf("mail: %w", err)
|
return fmt.Errorf("mail: %w", err)
|
||||||
}
|
}
|
||||||
for _, recipient := range to {
|
for _, recipient := range to {
|
||||||
@@ -121,3 +123,13 @@ func buildEmail(from string, to []string, subject, body string) []byte {
|
|||||||
sb.WriteString(body)
|
sb.WriteString(body)
|
||||||
return []byte(sb.String())
|
return []byte(sb.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractEmailAddr returns the bare address from "Name <addr@host>" or the original string.
|
||||||
|
func extractEmailAddr(from string) string {
|
||||||
|
start := strings.LastIndex(from, "<")
|
||||||
|
end := strings.LastIndex(from, ">")
|
||||||
|
if start >= 0 && end > start {
|
||||||
|
return strings.TrimSpace(from[start+1 : end])
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(from)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user