feat: SMTP Compatibility Enhancement and SSL Protocol Support (#174)

This commit is contained in:
Deng Junhai 2024-06-23 03:04:52 +08:00
parent 9d4ff7285a
commit 6f3cdad1e7
8 changed files with 58 additions and 9 deletions

View File

@ -20,6 +20,7 @@ export type GeneralState = {
export type MailState = {
host: string;
protocol: boolean;
port: number;
username: string;
password: string;
@ -137,6 +138,7 @@ export const initialSystemState: SystemProps = {
auth_footer: false,
},
mail: {
protocol: false,
host: "",
port: 465,
username: "",

View File

@ -704,6 +704,7 @@
"debugMode": "调试模式",
"debugModeTip": "调试模式,开启后日志将输出详细的请求参数等的日志,用于排查问题",
"mailHost": "发件域名",
"mailProtocol": "发件协议",
"mailPort": "SMTP 端口",
"mailUser": "用户名",
"mailPass": "密码",

View File

@ -513,6 +513,7 @@
"backend": "Backend Domain",
"backendTip": "Backend domain name (docker installation default path is/api), used to receive callbacks and storage, etc., default is empty\nExample: {{backend}}",
"mailHost": "Mail Host",
"mailProtocol": "Mail Protocol",
"mailPort": "SMTP Port",
"mailUser": "Username",
"mailPass": "Password",

View File

@ -513,6 +513,7 @@
"backend": "バックエンドドメイン",
"backendTip": "バックエンドドメイン名( dockerインストールのデフォルトパスは/api )、コールバックやストレージなどを受信するために使用、デフォルトは空です\n例{{ backend}}",
"mailHost": "送信ドメイン名",
"mailProtocol": "送信プロトコル",
"mailPort": "SMTPポート",
"mailUser": "ユーザー名",
"mailPass": "パスワード",

View File

@ -513,6 +513,7 @@
"backend": "Домен бэкэнда",
"backendTip": "Имя домена бэкенда (путь установки докера по умолчанию -/api), используется для получения обратных вызовов и хранения и т. д., значение по умолчанию пусто\nПример: {{backend}}",
"mailHost": "Почтовый хост",
"mailProtocol": "Протокол отправки",
"mailPort": "Порт SMTP",
"mailUser": "Имя пользователя",
"mailPass": "Пароль",

View File

@ -12,6 +12,13 @@ import Paragraph, {
ParagraphSpace,
} from "@/components/Paragraph.tsx";
import { Button } from "@/components/ui/button.tsx";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select.tsx";
import { Label } from "@/components/ui/label.tsx";
import { Input } from "@/components/ui/input.tsx";
import { useMemo, useReducer, useState } from "react";
@ -283,8 +290,8 @@ function Mail({ data, dispatch, onChange }: CompProps<MailState>) {
data.username.length > 0 &&
data.password.length > 0 &&
data.from.length > 0 &&
/\w+@\w+\.\w+/.test(data.from) &&
!data.username.includes("@")
data.username.includes("@") &&
!/\w+@/.test(data.from)
);
}, [data]);
@ -332,6 +339,30 @@ function Mail({ data, dispatch, onChange }: CompProps<MailState>) {
placeholder={`smtp.qcloudmail.com`}
/>
</ParagraphItem>
<ParagraphItem>
<Label>
<Require /> {t("admin.system.mailProtocol")}
</Label>
<Select
value={data.protocol ? "true" : "false"}
onValueChange={(value: string) => {
dispatch({
type: "update:mail.protocol",
value: value === "true",
});
}}
>
<SelectTrigger className={`select`}>
<SelectValue
placeholder={data.protocol ? t("admin.system.mailProtocolTLS") : t("admin.system.mailProtocolSSL")}
/>
</SelectTrigger>
<SelectContent>
<SelectItem value="true">TLS</SelectItem>
<SelectItem value="false">SSL</SelectItem>
</SelectContent>
</Select>
</ParagraphItem>
<ParagraphItem>
<Label>
<Require /> {t("admin.system.mailPort")}
@ -360,7 +391,7 @@ function Mail({ data, dispatch, onChange }: CompProps<MailState>) {
}
className={cn(
"transition-all duration-300",
data.username.includes("@") && `border-red-700`,
!data.username.includes("@") && `border-red-700`,
)}
placeholder={t("admin.system.mailUser")}
/>
@ -396,7 +427,7 @@ function Mail({ data, dispatch, onChange }: CompProps<MailState>) {
className={cn(
"transition-all duration-300",
data.from.length > 0 &&
!/\w+@\w+\.\w+/.test(data.from) &&
!/\w+@/.test(data.from) &&
`border-red-700`,
)}
/>

View File

@ -4,8 +4,9 @@ import (
"chat/globals"
"chat/utils"
"fmt"
"github.com/spf13/viper"
"strings"
"github.com/spf13/viper"
)
type ApiInfo struct {
@ -54,6 +55,7 @@ type whiteList struct {
type mailState struct {
Host string `json:"host" mapstructure:"host"`
Protocol bool `json:"protocol" mapstructure:"protocol"`
Port int `json:"port" mapstructure:"port"`
Username string `json:"username" mapstructure:"username"`
Password string `json:"password" mapstructure:"password"`
@ -162,6 +164,7 @@ func (c *SystemConfig) GetBackend() string {
func (c *SystemConfig) GetMail() *utils.SmtpPoster {
return utils.NewSmtpPoster(
c.Mail.Host,
c.Mail.Protocol,
c.Mail.Port,
c.Mail.Username,
c.Mail.Password,

View File

@ -3,22 +3,25 @@ package utils
import (
"bytes"
"fmt"
"gopkg.in/mail.v2"
"strings"
"text/template"
"gopkg.in/mail.v2"
)
type SmtpPoster struct {
Host string
Protocol bool
Port int
Username string
Password string
From string
}
func NewSmtpPoster(host string, port int, username string, password string, from string) *SmtpPoster {
func NewSmtpPoster(host string, protocol bool, port int, username string, password string, from string) *SmtpPoster {
return &SmtpPoster{
Host: host,
Protocol: protocol,
Port: port,
Username: username,
Password: password,
@ -35,14 +38,20 @@ func (s *SmtpPoster) SendMail(to string, subject string, body string) error {
return fmt.Errorf("smtp not configured properly")
}
dialer := mail.NewDialer(s.Host, s.Port, s.From, s.Password)
dialer := mail.NewDialer(s.Host, s.Port, s.Username, s.Password)
message := mail.NewMessage()
message.SetHeader("From", fmt.Sprintf("%s <%s>", s.Username, s.From))
message.SetHeader("From", s.From)
message.SetHeader("To", to)
message.SetHeader("Subject", subject)
message.SetBody("text/html", body)
if s.Protocol {
dialer.StartTLSPolicy = mail.MandatoryStartTLS
} else {
dialer.StartTLSPolicy = mail.NoStartTLS
}
// outlook STARTTLS policy adapter
if strings.Contains(s.Host, "outlook") {
dialer.StartTLSPolicy = mail.MandatoryStartTLS