chore: add mailtest tool and local config template

This commit is contained in:
2026-03-01 22:32:48 +08:00
parent dbfec3645b
commit a258923892
2 changed files with 141 additions and 0 deletions

103
cmd/mailtest/main.go Normal file
View File

@@ -0,0 +1,103 @@
package main
import (
"crypto/tls"
"fmt"
"log"
"net"
"net/smtp"
"os"
"strings"
"time"
)
func main() {
smtpHost := getenv("SMTP_HOST", "smtp.163.com")
smtpPort := getenv("SMTP_PORT", "465")
smtpUser := strings.TrimSpace(os.Getenv("SMTP_USER"))
smtpPass := strings.TrimSpace(os.Getenv("SMTP_PASS"))
mailTo := strings.TrimSpace(os.Getenv("MAIL_TO"))
subject := getenv("MAIL_SUBJECT", "SuperTodo SMTP test")
body := getenv("MAIL_BODY", "This is a SMTP connectivity test email from SuperTodo.")
if smtpUser == "" || smtpPass == "" || mailTo == "" {
log.Fatal("missing required env: SMTP_USER, SMTP_PASS, MAIL_TO")
}
if err := sendMailTLS(smtpHost, smtpPort, smtpUser, smtpPass, mailTo, subject, body); err != nil {
log.Fatalf("send mail failed: %v", err)
}
log.Printf("mail sent successfully: from=%s to=%s via %s:%s", smtpUser, mailTo, smtpHost, smtpPort)
}
func sendMailTLS(host, port, user, pass, to, subject, body string) error {
addr := net.JoinHostPort(host, port)
dialer := &net.Dialer{Timeout: 10 * time.Second}
conn, err := tls.DialWithDialer(dialer, "tcp", addr, &tls.Config{
ServerName: host,
MinVersion: tls.VersionTLS12,
})
if err != nil {
return fmt.Errorf("tls dial failed: %w", err)
}
defer conn.Close()
client, err := smtp.NewClient(conn, host)
if err != nil {
return fmt.Errorf("smtp client failed: %w", err)
}
defer client.Close()
auth := smtp.PlainAuth("", user, pass, host)
if err := client.Auth(auth); err != nil {
return fmt.Errorf("smtp auth failed: %w", err)
}
if err := client.Mail(user); err != nil {
return fmt.Errorf("mail from failed: %w", err)
}
if err := client.Rcpt(to); err != nil {
return fmt.Errorf("rcpt to failed: %w", err)
}
w, err := client.Data()
if err != nil {
return fmt.Errorf("data failed: %w", err)
}
msg := buildMessage(user, to, subject, body)
if _, err := w.Write([]byte(msg)); err != nil {
return fmt.Errorf("write message failed: %w", err)
}
if err := w.Close(); err != nil {
return fmt.Errorf("close writer failed: %w", err)
}
if err := client.Quit(); err != nil {
return fmt.Errorf("smtp quit failed: %w", err)
}
return nil
}
func buildMessage(from, to, subject, body string) string {
var b strings.Builder
b.WriteString("From: " + from + "\r\n")
b.WriteString("To: " + to + "\r\n")
b.WriteString("Subject: " + subject + "\r\n")
b.WriteString("MIME-Version: 1.0\r\n")
b.WriteString("Content-Type: text/plain; charset=UTF-8\r\n")
b.WriteString("\r\n")
b.WriteString(body)
if !strings.HasSuffix(body, "\n") {
b.WriteString("\r\n")
}
return b.String()
}
func getenv(key, fallback string) string {
v := strings.TrimSpace(os.Getenv(key))
if v == "" {
return fallback
}
return v
}

38
config.toml Normal file
View File

@@ -0,0 +1,38 @@
[app]
name = "super-todo"
env = "dev"
http_addr = ":8080"
[database]
url = "postgres://todo:todo@localhost:5432/todo?sslmode=disable"
[auth]
secret = "dev-secret-change-me"
access_token_ttl_minutes = 15
refresh_token_ttl_hours = 168
[redis]
addr = "localhost:6379"
password = ""
db = 0
[kafka]
brokers = ["localhost:29092"]
topic = "todo.tasks"
[mail.smtp]
host = "smtp.qq.com"
port = 465
username = "2914037183@qq.com"
password = "daxnelwgfaraddbi"
from = "2914037183@qq.com"
use_tls = true
[notification]
enabled = true
timezone = "Asia/Shanghai"
[notification.schedule]
daily_summary_cron = "0 30 9 * * *"
overdue_reminder_cron = "0 0/30 * * * *"