diff --git a/fe/src/i18n/i18n.js b/fe/src/i18n/i18n.js
index 3890587..4b26e7c 100644
--- a/fe/src/i18n/i18n.js
+++ b/fe/src/i18n/i18n.js
@@ -86,6 +86,7 @@ var lang = {
"move":"Move to group",
"del_rule_confirm":"Are you sure to delete this?",
"rule_params":"Executed params",
+ "autoSSLWarn":"PMail is not currently running on port 80. If you want PMail to manage SSL certificates automatically, please forward the /.well-known/* route to PMail. See https://github.com/Jinnrry/PMail/issues/94 for details."
};
@@ -178,6 +179,7 @@ var zhCN = {
"move":"移动分组",
"del_rule_confirm":"确定要删除吗?",
"rule_params":"执行参数",
+ "autoSSLWarn":"PMail当前未使用80端口启动,如果想要PMail自动管理SSL证书,请将/.well-known/*路由转发到PMail。 详见https://github.com/Jinnrry/PMail/issues/94"
}
switch (navigator.language) {
diff --git a/fe/src/views/SetupView.vue b/fe/src/views/SetupView.vue
index fa9f6dc..3b4df5a 100644
--- a/fe/src/views/SetupView.vue
+++ b/fe/src/views/SetupView.vue
@@ -95,8 +95,8 @@
-
+
{{ lang.setDNS }}
{{ lang.dns_desc }}
@@ -121,6 +121,10 @@
+
+
{{ lang.setSSL }}
@@ -142,9 +146,11 @@
-
+
+
+
{{
@@ -192,6 +198,8 @@ const fullscreenLoading = ref(false)
const dnsInfos = ref([
])
+const port = ref(80)
+
const setPassword = () => {
if (adminSettings.hadSeted) {
active.value++;
@@ -279,7 +287,8 @@ const getSSLConfig = () => {
if (res.errorNo != 0) {
ElMessage.error(res.errorMsg)
} else {
- sslSettings.type = res.data
+ sslSettings.type = res.data.type
+ port.value = res.data.port
}
})
}
@@ -368,6 +377,5 @@ const next = () => {
flex-direction: column;
}
-
#next {}
\ No newline at end of file
diff --git a/server/config/config.go b/server/config/config.go
index 68bb94f..fca85a7 100644
--- a/server/config/config.go
+++ b/server/config/config.go
@@ -33,6 +33,15 @@ type Config struct {
WebPushToken string `json:"webPushToken"`
Tables map[string]string `json:"-"`
TablesInitData map[string]string `json:"-"`
+ setupPort int // 初始化阶段端口
+}
+
+func (c *Config) GetSetupPort() int {
+ return c.setupPort
+}
+
+func (c *Config) SetSetupPort(setupPort int) {
+ c.setupPort = setupPort
}
const DBTypeMySQL = "mysql"
diff --git a/server/controllers/email/send.go b/server/controllers/email/send.go
index 417e7fa..b141133 100644
--- a/server/controllers/email/send.go
+++ b/server/controllers/email/send.go
@@ -1,9 +1,11 @@
package email
import (
+ "database/sql"
"encoding/base64"
"encoding/json"
log "github.com/sirupsen/logrus"
+ "github.com/spf13/cast"
"io"
"net/http"
"pmail/config"
@@ -13,6 +15,7 @@ import (
"pmail/hooks"
"pmail/hooks/framework"
"pmail/i18n"
+ "pmail/models"
"pmail/utils/async"
"pmail/utils/context"
"pmail/utils/send"
@@ -107,6 +110,18 @@ func Send(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
Name: reqData.From.Name,
EmailAddress: reqData.From.Email,
}
+ if reqData.Sender.Email != "" {
+ e.Sender = &parsemail.User{
+ Name: reqData.Sender.Name,
+ EmailAddress: reqData.Sender.Email,
+ }
+ } else {
+ e.Sender = &parsemail.User{
+ Name: reqData.From.Name,
+ EmailAddress: reqData.From.Email,
+ }
+ }
+
e.Text = []byte(reqData.Text)
e.HTML = []byte(reqData.HTML)
e.Subject = reqData.Subject
@@ -138,36 +153,36 @@ func Send(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
}
log.WithContext(ctx).Debugf("插件执行--SendBefore End")
- // 邮件落库
- sql := "INSERT INTO email (type,subject, reply_to, from_name, from_address, `to`, bcc, cc, text, html, sender, attachments,spf_check, dkim_check, create_time,send_user_id,error) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
- sqlRes, sqlerr := db.Instance.Exec(db.WithContext(ctx, sql),
- 1,
- e.Subject,
- json2string(e.ReplyTo),
- e.From.Name,
- e.From.EmailAddress,
- json2string(e.To),
- json2string(e.Bcc),
- json2string(e.Cc),
- e.Text,
- e.HTML,
- json2string(e.Sender),
- json2string(e.Attachments),
- 1,
- 1,
- time.Now(),
- ctx.UserID,
- "",
- )
- emailId, _ := sqlRes.LastInsertId()
+ modelEmail := models.Email{
+ Type: 1,
+ Subject: e.Subject,
+ ReplyTo: json2string(e.ReplyTo),
+ FromName: e.From.Name,
+ FromAddress: e.From.EmailAddress,
+ To: json2string(e.To),
+ Bcc: json2string(e.Bcc),
+ Cc: json2string(e.Cc),
+ Text: sql.NullString{String: string(e.Text), Valid: true},
+ Html: sql.NullString{String: string(e.HTML), Valid: true},
+ Sender: json2string(e.Sender),
+ Attachments: json2string(e.Attachments),
+ SPFCheck: 1,
+ DKIMCheck: 1,
+ SendUserID: ctx.UserID,
+ SendDate: time.Now(),
+ Status: 1,
+ CreateTime: time.Now(),
+ }
- if sqlerr != nil || emailId <= 0 {
+ _, err = db.Instance.Insert(&modelEmail)
+
+ if err != nil || modelEmail.Id <= 0 {
log.Println("mysql insert error:", err.Error())
response.NewErrorResponse(response.ServerError, i18n.GetText(ctx.Lang, "send_fail"), err.Error()).FPrint(w)
return
}
- e.MessageId = emailId
+ e.MessageId = cast.ToInt64(modelEmail.Id)
async.New(ctx).Process(func(p any) {
errMsg := ""
@@ -189,12 +204,12 @@ func Send(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
if err != nil {
errMsg = err.Error()
- _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =2 ,error=? where id = ? "), errMsg, emailId)
+ _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =2 ,error=? where id = ? "), errMsg, modelEmail.Id)
if err != nil {
log.WithContext(ctx).Errorf("sql Error :%+v", err)
}
} else {
- _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =1 where id = ? "), emailId)
+ _, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =1 where id = ? "), modelEmail.Id)
if err != nil {
log.WithContext(ctx).Errorf("sql Error :%+v", err)
}
diff --git a/server/controllers/setup.go b/server/controllers/setup.go
index c955a0d..5d530da 100644
--- a/server/controllers/setup.go
+++ b/server/controllers/setup.go
@@ -26,6 +26,11 @@ func AcmeChallenge(w http.ResponseWriter, r *http.Request) {
}
}
+type sslResponse struct {
+ Port int `json:"port"`
+ Type string `json:"type"`
+}
+
func Setup(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
reqBytes, err := io.ReadAll(req.Body)
if err != nil {
@@ -121,7 +126,11 @@ func Setup(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
if reqData["step"] == "ssl" && reqData["action"] == "get" {
sslType := ssl.GetSSL()
- response.NewSuccessResponse(sslType).FPrint(w)
+ res := sslResponse{
+ Type: sslType,
+ Port: config.Instance.GetSetupPort(),
+ }
+ response.NewSuccessResponse(res).FPrint(w)
return
}
diff --git a/server/http_server/setup_server.go b/server/http_server/setup_server.go
index 8ad74a4..8dc47f7 100644
--- a/server/http_server/setup_server.go
+++ b/server/http_server/setup_server.go
@@ -6,12 +6,12 @@ import (
log "github.com/sirupsen/logrus"
"io/fs"
"net/http"
+ "pmail/config"
"pmail/controllers"
+ "pmail/utils/ip"
"time"
)
-var ip string
-
// 项目初始化引导用的服务,初始化引导结束后即退出
var setupServer *http.Server
@@ -29,7 +29,14 @@ func SetupStart() {
HttpPort := 80
flag.IntVar(&HttpPort, "p", 80, "初始化阶段Http服务端口")
flag.Parse()
+ config.Instance.SetSetupPort(HttpPort)
log.Infof("HttpServer Start On Port :%d", HttpPort)
+ if HttpPort == 80 {
+ log.Infof("Please click http://%s to continue.\n", ip.GetIp())
+ } else {
+ log.Infof("Please click http://%s:%d to continue.", ip.GetIp(), HttpPort)
+ }
+
setupServer = &http.Server{
Addr: fmt.Sprintf(":%d", HttpPort),
Handler: mux,
diff --git a/server/res_init/init.go b/server/res_init/init.go
index 2358b6b..e587813 100644
--- a/server/res_init/init.go
+++ b/server/res_init/init.go
@@ -23,7 +23,6 @@ func Init(serverVersion string) {
if !config.IsInit {
dirInit()
- log.Infof("Please click http://127.0.0.1 to continue.\n")
go http_server.SetupStart()
<-signal.InitChan
http_server.SetupStop()
diff --git a/server/services/setup/dns.go b/server/services/setup/dns.go
index 6282fcd..f3cd6e2 100644
--- a/server/services/setup/dns.go
+++ b/server/services/setup/dns.go
@@ -1,14 +1,12 @@
package setup
import (
- "encoding/json"
"fmt"
- "io"
- "net/http"
"pmail/i18n"
"pmail/services/auth"
"pmail/utils/context"
"pmail/utils/errors"
+ "pmail/utils/ip"
)
type DNSItem struct {
@@ -26,30 +24,11 @@ func GetDNSSettings(ctx *context.Context) ([]*DNSItem, error) {
}
ret := []*DNSItem{
- {Type: "A", Host: "smtp", Value: getIp(), TTL: 3600, Tips: i18n.GetText(ctx.Lang, "ip_taps")},
- {Type: "A", Host: "pop", Value: getIp(), TTL: 3600, Tips: i18n.GetText(ctx.Lang, "ip_taps")},
+ {Type: "A", Host: "smtp", Value: ip.GetIp(), TTL: 3600, Tips: i18n.GetText(ctx.Lang, "ip_taps")},
+ {Type: "A", Host: "pop", Value: ip.GetIp(), TTL: 3600, Tips: i18n.GetText(ctx.Lang, "ip_taps")},
{Type: "MX", Host: "-", Value: fmt.Sprintf("smtp.%s", configData.Domain), TTL: 3600},
{Type: "TXT", Host: "-", Value: "v=spf1 a mx ~all", TTL: 3600},
{Type: "TXT", Host: "default._domainkey", Value: auth.DkimGen(), TTL: 3600},
}
return ret, nil
}
-
-func getIp() string {
- resp, err := http.Get("http://ip-api.com/json/?lang=zh-CN ")
- if err != nil {
- return "Your Server IP"
- }
- defer resp.Body.Close()
-
- if resp.StatusCode == 200 {
- body, err := io.ReadAll(resp.Body)
- if err == nil {
- var queryRes map[string]string
- _ = json.Unmarshal(body, &queryRes)
-
- return queryRes["query"]
- }
- }
- return "Your Server IP"
-}
diff --git a/server/utils/ip/ip.go b/server/utils/ip/ip.go
new file mode 100644
index 0000000..ca24939
--- /dev/null
+++ b/server/utils/ip/ip.go
@@ -0,0 +1,32 @@
+package ip
+
+import (
+ "encoding/json"
+ "io"
+ "net/http"
+)
+
+var ip string
+
+func GetIp() string {
+ if ip != "" {
+ return ip
+ }
+
+ resp, err := http.Get("http://ip-api.com/json/?lang=zh-CN ")
+ if err != nil {
+ return "[Your Server IP]"
+ }
+ defer resp.Body.Close()
+
+ if resp.StatusCode == 200 {
+ body, err := io.ReadAll(resp.Body)
+ if err == nil {
+ var queryRes map[string]string
+ _ = json.Unmarshal(body, &queryRes)
+ ip = queryRes["query"]
+ return queryRes["query"]
+ }
+ }
+ return "[Your Server IP]"
+}
diff --git a/server/utils/send/send.go b/server/utils/send/send.go
index 31c543c..43a9336 100644
--- a/server/utils/send/send.go
+++ b/server/utils/send/send.go
@@ -188,7 +188,12 @@ func Send(ctx *context.Context, e *parsemail.Email) (error, map[string]error) {
orgMap := map[string]error{}
errMap.Range(func(key, value any) bool {
- orgMap[key.(string)] = value.(error)
+ if value != nil {
+ orgMap[key.(string)] = value.(error)
+ }else {
+ orgMap[key.(string)] = nil
+ }
+
return true
})