parent
e95930cc1a
commit
096b4b8fed
23
Dockerfile
23
Dockerfile
@ -9,14 +9,13 @@ RUN yarn && yarn build
|
||||
FROM golang:alpine as serverbuild
|
||||
ARG VERSION
|
||||
WORKDIR /work
|
||||
|
||||
COPY --from=febuild /work/dist /work/http_server/dist
|
||||
|
||||
COPY . .
|
||||
COPY --from=febuild /work/dist /work/server/http_server/dist
|
||||
RUN apk update && apk add git
|
||||
RUN go build -ldflags "-s -w -X 'main.version=${VERSION}' -X 'main.goVersion=$(go version)' -X 'main.gitHash=$(git show -s --format=%H)' -X 'main.buildTime=$(TZ=UTC-8 date +%Y-%m-%d" "%H:%M:%S)'" -o pmail main.go
|
||||
RUN cd /work/hooks/telegram_push && go build -ldflags "-s -w" -o output/telegram_push telegram_push.go
|
||||
RUN cd /work/hooks/web_push && go build -ldflags "-s -w" -o output/web_push web_push.go
|
||||
RUN cd /work/hooks/wechat_push && go build -ldflags "-s -w" -o output/wechat_push wechat_push.go
|
||||
RUN cd /work/server && go build -ldflags "-s -w -X 'main.version=${VERSION}' -X 'main.goVersion=$(go version)' -X 'main.gitHash=$(git show -s --format=%H)' -X 'main.buildTime=$(TZ=UTC-8 date +%Y-%m-%d" "%H:%M:%S)'" -o pmail main.go
|
||||
RUN cd /work/server/hooks/telegram_push && go build -ldflags "-s -w" -o output/telegram_push telegram_push.go
|
||||
RUN cd /work/server/hooks/web_push && go build -ldflags "-s -w" -o output/web_push web_push.go
|
||||
RUN cd /work/server/hooks/wechat_push && go build -ldflags "-s -w" -o output/wechat_push wechat_push.go
|
||||
|
||||
|
||||
FROM alpine
|
||||
@ -31,9 +30,11 @@ RUN apk add --no-cache tzdata \
|
||||
&&rm -rf /var/cache/apk/* /tmp/* /var/tmp/* $HOME/.cache
|
||||
|
||||
|
||||
COPY --from=serverbuild /work/pmail .
|
||||
COPY --from=serverbuild /work/hooks/telegram_push/output/* ./plugins/
|
||||
COPY --from=serverbuild /work/hooks/web_push/output/* ./plugins/
|
||||
COPY --from=serverbuild /work/hooks/wechat_push/output/* ./plugins/
|
||||
COPY --from=serverbuild /work/server/pmail .
|
||||
COPY --from=serverbuild /work/server/hooks/telegram_push/output/* ./plugins/
|
||||
COPY --from=serverbuild /work/server/hooks/web_push/output/* ./plugins/
|
||||
COPY --from=serverbuild /work/server/hooks/wechat_push/output/* ./plugins/
|
||||
|
||||
EXPOSE 25 80 110 443 465 995
|
||||
|
||||
CMD /work/pmail
|
||||
|
||||
@ -29,4 +29,6 @@ COPY --from=serverbuild /work/hooks/telegram_push/output/* ./plugins/
|
||||
COPY --from=serverbuild /work/hooks/web_push/output/* ./plugins/
|
||||
COPY --from=serverbuild /work/hooks/wechat_push/output/* ./plugins/
|
||||
|
||||
EXPOSE 25 80 110 443 465 995
|
||||
|
||||
CMD /work/pmail
|
||||
|
||||
@ -103,9 +103,9 @@ SMTP Port: 25/465(SSL)
|
||||
|
||||
[WeChat Push](server/hooks/wechat_push/README.md)
|
||||
|
||||
[Telegram Push](server/hooks/wechat_push/README.md)
|
||||
[Telegram Push](server/hooks/telegram_push/README.md)
|
||||
|
||||
[Web Push](server/hooks/wechat_push/README.md)
|
||||
[Web Push](server/hooks/web_push/README.md)
|
||||
|
||||
## Plugin Install
|
||||
> [!IMPORTANT]
|
||||
@ -125,6 +125,11 @@ The code is in `fe` folder.
|
||||
|
||||
The code is in `server` folder.
|
||||
|
||||
3、How to build
|
||||
|
||||
`make build`
|
||||
|
||||
|
||||
## Api Documentation
|
||||
|
||||
[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)
|
||||
|
||||
@ -106,9 +106,9 @@ SMTP端口: 25/465(SSL)
|
||||
|
||||
[微信推送](server/hooks/wechat_push/README.md)
|
||||
|
||||
[Telegram推送](server/hooks/wechat_push/README.md)
|
||||
[Telegram推送](server/hooks/telegram_push/README.md)
|
||||
|
||||
[WebHook推送](server/hooks/wechat_push/README.md)
|
||||
[WebHook推送](server/hooks/web_push/README.md)
|
||||
|
||||
## 插件安装
|
||||
> [!IMPORTANT]
|
||||
@ -128,6 +128,10 @@ SMTP端口: 25/465(SSL)
|
||||
|
||||
后端代码进入 `server`文件夹,运行 `main.go`文件
|
||||
|
||||
3、编译该项目
|
||||
|
||||
`make build`
|
||||
|
||||
## 后端接口文档
|
||||
|
||||
[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)
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
"SSLPublicKeyPath": "config/ssl/public.crt",
|
||||
"dbDSN": "./config/pmail.db",
|
||||
"dbType": "sqlite",
|
||||
"spamFilterLevel": 2,
|
||||
"spamFilterLevel": 1,
|
||||
"httpPort": 80,
|
||||
"httpsPort": 443,
|
||||
"isInit": true,
|
||||
|
||||
@ -8,17 +8,9 @@
|
||||
"SSLPublicKeyPath": "config/ssl/public.crt",
|
||||
"dbDSN": "root:root@tcp(127.0.0.1:3306)/pmail?parseTime=True&loc=Local",
|
||||
"dbType": "mysql",
|
||||
"spamFilterLevel": 2,
|
||||
"spamFilterLevel": 1,
|
||||
"httpPort": 80,
|
||||
"httpsPort": 443,
|
||||
"weChatPushAppId": "",
|
||||
"weChatPushSecret": "",
|
||||
"weChatPushTemplateId": "",
|
||||
"weChatPushUserId": "",
|
||||
"tgChatId": "",
|
||||
"tgBotToken": "",
|
||||
"webPushUrl": "",
|
||||
"webPushToken": "",
|
||||
"isInit": true,
|
||||
"httpsEnabled": 2
|
||||
}
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"io"
|
||||
"net/textproto"
|
||||
"pmail/config"
|
||||
"pmail/utils/array"
|
||||
"pmail/utils/context"
|
||||
"regexp"
|
||||
"strings"
|
||||
@ -145,37 +144,34 @@ func BuilderUser(str string) *User {
|
||||
return buildUser(str)
|
||||
}
|
||||
|
||||
var emailAddressRe = regexp.MustCompile(`<(.*@.*)>`)
|
||||
|
||||
func buildUser(str string) *User {
|
||||
if str == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
ret := &User{}
|
||||
args := strings.Split(str, " ")
|
||||
if len(args) == 1 {
|
||||
|
||||
matched := emailAddressRe.FindStringSubmatch(str)
|
||||
|
||||
if len(matched) == 2 {
|
||||
ret.EmailAddress = matched[1]
|
||||
} else {
|
||||
ret.EmailAddress = str
|
||||
return ret
|
||||
}
|
||||
|
||||
if len(args) > 2 {
|
||||
targs := []string{
|
||||
array.Join(args[0:len(args)-1], " "),
|
||||
args[len(args)-1],
|
||||
}
|
||||
args = targs
|
||||
}
|
||||
str = strings.ReplaceAll(str, matched[0], "")
|
||||
|
||||
args[0] = strings.Trim(args[0], "\"")
|
||||
args[1] = strings.TrimPrefix(args[1], "<")
|
||||
args[1] = strings.TrimSuffix(args[1], ">")
|
||||
str = strings.Trim(strings.TrimSpace(str), "\"")
|
||||
|
||||
name, err := (&WordDecoder{}).Decode(strings.ReplaceAll(args[0], "\"", ""))
|
||||
name, err := (&WordDecoder{}).Decode(strings.ReplaceAll(str, "\"", ""))
|
||||
if err == nil {
|
||||
ret.Name = name
|
||||
ret.Name = strings.TrimSpace(name)
|
||||
} else {
|
||||
ret.Name = args[0]
|
||||
ret.Name = strings.TrimSpace(str)
|
||||
}
|
||||
ret.EmailAddress = args[1]
|
||||
return ret
|
||||
}
|
||||
|
||||
|
||||
@ -77,6 +77,22 @@ func Test_buildUser(t *testing.T) {
|
||||
if u.Name != "Jinnrry N" {
|
||||
t.Error("error")
|
||||
}
|
||||
|
||||
u = buildUser("=?UTF-8?B?YWRtaW5AamlubnJyeS5jb20=?=<admin@jinnrry.com>")
|
||||
if u.EmailAddress != "admin@jinnrry.com" {
|
||||
t.Error("error")
|
||||
}
|
||||
if u.Name != "admin@jinnrry.com" {
|
||||
t.Error("error")
|
||||
}
|
||||
|
||||
u = buildUser("\"admin@jinnrry.com\" <admin@jinnrry.com>")
|
||||
if u.EmailAddress != "admin@jinnrry.com" {
|
||||
t.Error("error")
|
||||
}
|
||||
if u.Name != "admin@jinnrry.com" {
|
||||
t.Error("error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmailBuidlers(t *testing.T) {
|
||||
|
||||
@ -1,51 +1,47 @@
|
||||
module pmail
|
||||
|
||||
go 1.21
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/Jinnrry/gopop v0.0.0-20231113115125-fbdf52ae39ea
|
||||
github.com/alexedwards/scs/mysqlstore v0.0.0-20230327161757-10d4299e3b24
|
||||
github.com/alexedwards/scs/sqlite3store v0.0.0-20231113091146-cef4b05350c8
|
||||
github.com/alexedwards/scs/v2 v2.5.1
|
||||
github.com/emersion/go-message v0.18.0
|
||||
github.com/emersion/go-msgauth v0.6.6
|
||||
github.com/emersion/go-smtp v0.20.1
|
||||
github.com/go-acme/lego/v4 v4.13.3
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/alexedwards/scs/mysqlstore v0.0.0-20240316134038-7e11d57e8885
|
||||
github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885
|
||||
github.com/alexedwards/scs/v2 v2.8.0
|
||||
github.com/emersion/go-message v0.18.1
|
||||
github.com/emersion/go-msgauth v0.6.8
|
||||
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
|
||||
github.com/emersion/go-smtp v0.21.0
|
||||
github.com/go-acme/lego/v4 v4.16.1
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/mileusna/spf v0.9.5
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cast v1.5.1
|
||||
golang.org/x/crypto v0.10.0
|
||||
github.com/spf13/cast v1.6.0
|
||||
golang.org/x/crypto v0.22.0
|
||||
golang.org/x/text v0.14.0
|
||||
modernc.org/sqlite v1.24.0
|
||||
modernc.org/sqlite v1.29.6
|
||||
)
|
||||
|
||||
replace github.com/emersion/go-smtp v0.20.1 => github.com/jinnrry/go-smtp v0.20.1
|
||||
|
||||
require (
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.17 // indirect
|
||||
github.com/miekg/dns v1.1.55 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/miekg/dns v1.1.58 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
golang.org/x/mod v0.11.0 // indirect
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
golang.org/x/tools v0.10.0 // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.40.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.13 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/opt v0.1.3 // indirect
|
||||
modernc.org/strutil v1.1.3 // indirect
|
||||
modernc.org/token v1.0.1 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.24.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.19.0 // indirect
|
||||
golang.org/x/tools v0.20.0 // indirect
|
||||
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
|
||||
modernc.org/libc v1.49.3 // indirect
|
||||
modernc.org/mathutil v1.6.0 // indirect
|
||||
modernc.org/memory v1.8.0 // indirect
|
||||
modernc.org/strutil v1.2.0 // indirect
|
||||
modernc.org/token v1.1.0 // indirect
|
||||
)
|
||||
|
||||
168
server/go.sum
168
server/go.sum
@ -1,120 +1,108 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/Jinnrry/gopop v0.0.0-20231113115125-fbdf52ae39ea h1:GISNlu8fPa2K+aySmHPSd9X0PG8GAAFEobq4XIqodMk=
|
||||
github.com/Jinnrry/gopop v0.0.0-20231113115125-fbdf52ae39ea/go.mod h1:xcI6e+jbXWN+T8EWOJtHbAku6pzNqyCHaFvzdeL1r2o=
|
||||
github.com/Jinnrry/scs/sqlite3store v0.0.0-20230803080525-914f01e0d379 h1:i6LB/3lgkRDupe3owyNXtH8dtQrdaReCLeAZKrWcqAE=
|
||||
github.com/Jinnrry/scs/sqlite3store v0.0.0-20230803080525-914f01e0d379/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss=
|
||||
github.com/alexedwards/scs/mysqlstore v0.0.0-20230327161757-10d4299e3b24 h1:1jXpX7IE/zuf9FZQJpqZNepXqW8mq6NLzplHDCA43HY=
|
||||
github.com/alexedwards/scs/mysqlstore v0.0.0-20230327161757-10d4299e3b24/go.mod h1:ShejCOaSJCEjCWjc7YBrgy2xd0Kp+wiyBdzTNQrAGn4=
|
||||
github.com/alexedwards/scs/sqlite3store v0.0.0-20230327161757-10d4299e3b24/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss=
|
||||
github.com/alexedwards/scs/sqlite3store v0.0.0-20231113091146-cef4b05350c8 h1:mnXnnXEjn8QIyv4KCN0+IjDlXA64qdq2hIVOmfNFeuY=
|
||||
github.com/alexedwards/scs/sqlite3store v0.0.0-20231113091146-cef4b05350c8/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss=
|
||||
github.com/alexedwards/scs/v2 v2.5.1 h1:EhAz3Kb3OSQzD8T+Ub23fKsiuvE0GzbF5Lgn0uTwM3Y=
|
||||
github.com/alexedwards/scs/v2 v2.5.1/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/alexedwards/scs/mysqlstore v0.0.0-20240316134038-7e11d57e8885 h1:C7QAamNjR5yz6di4KJWAKcnxueKBgq4L/JGXhlnu35w=
|
||||
github.com/alexedwards/scs/mysqlstore v0.0.0-20240316134038-7e11d57e8885/go.mod h1:p8jK3D80sw1PFrCSdlcJF1O75bp55HqbgDyyCLM0FrE=
|
||||
github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885 h1:+DCxWg/ojncqS+TGAuRUoV7OfG/S4doh0pcpAwEcow0=
|
||||
github.com/alexedwards/scs/sqlite3store v0.0.0-20240316134038-7e11d57e8885/go.mod h1:Iyk7S76cxGaiEX/mSYmTZzYehp4KfyylcLaV3OnToss=
|
||||
github.com/alexedwards/scs/v2 v2.8.0 h1:h31yUYoycPuL0zt14c0gd+oqxfRwIj6SOjHdKRZxhEw=
|
||||
github.com/alexedwards/scs/v2 v2.8.0/go.mod h1:ToaROZxyKukJKT/xLcVQAChi5k6+Pn1Gvmdl7h3RRj8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/emersion/go-message v0.11.2/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY=
|
||||
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
|
||||
github.com/emersion/go-message v0.18.0 h1:7LxAXHRpSeoO/Wom3ZApVZYG7c3d17yCScYce8WiXA8=
|
||||
github.com/emersion/go-message v0.18.0/go.mod h1:Zi69ACvzaoV/MBnrxfVBPV3xWEuCmC2nEN39oJF4B8A=
|
||||
github.com/emersion/go-milter v0.3.3/go.mod h1:ablHK0pbLB83kMFBznp/Rj8aV+Kc3jw8cxzzmCNLIOY=
|
||||
github.com/emersion/go-msgauth v0.6.6 h1:buv5lL8v/3v4RpHnQFS2IPhE3nxSRX+AxnrEJbDbHhA=
|
||||
github.com/emersion/go-msgauth v0.6.6/go.mod h1:A+/zaz9bzukLM6tRWRgJ3BdrBi+TFKTvQ3fGMFOI9SM=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
||||
github.com/emersion/go-message v0.18.1 h1:tfTxIoXFSFRwWaZsgnqS1DSZuGpYGzSmCZD8SK3QA2E=
|
||||
github.com/emersion/go-message v0.18.1/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
|
||||
github.com/emersion/go-msgauth v0.6.8 h1:kW/0E9E8Zx5CdKsERC/WnAvnXvX7q9wTHia1OA4944A=
|
||||
github.com/emersion/go-msgauth v0.6.8/go.mod h1:YDwuyTCUHu9xxmAeVj0eW4INnwB6NNZoPdLerpSxRrc=
|
||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 h1:IbFBtwoTQyw0fIM5xv1HF+Y+3ZijDR839WMulgxCcUY=
|
||||
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/go-acme/lego/v4 v4.13.3 h1:aZ1S9FXIkCWG3Uw/rZKSD+MOuO8ZB1t6p9VCg6jJiNY=
|
||||
github.com/go-acme/lego/v4 v4.13.3/go.mod h1:c/iodVGMeBXG/+KiQczoNkySo3YLWTVa0kiyeVd/FHc=
|
||||
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
|
||||
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
|
||||
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY=
|
||||
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||
github.com/emersion/go-smtp v0.21.0 h1:ZDZmX9aFUuPlD1lpoT0nC/nozZuIkSCyQIyxdijjCy0=
|
||||
github.com/emersion/go-smtp v0.21.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/go-acme/lego/v4 v4.16.1 h1:JxZ93s4KG0jL27rZ30UsIgxap6VGzKuREsSkkyzeoCQ=
|
||||
github.com/go-acme/lego/v4 v4.16.1/go.mod h1:AVvwdPned/IWpD/ihHhMsKnveF7HHYAz/CmtXi7OZoE=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
|
||||
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jinnrry/go-smtp v0.20.1 h1:coy2+Ch7+ptr3J4rHwE+YVY25eaXuUbi4PNHchfc6ro=
|
||||
github.com/jinnrry/go-smtp v0.20.1/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
|
||||
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/martinlindhe/base36 v1.0.0/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
|
||||
github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4=
|
||||
github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY=
|
||||
github.com/mileusna/spf v0.9.5 h1:P6cmaIBwrhZaP9stXMzGOtxe+gIu65OVbZCmrAv9rgU=
|
||||
github.com/mileusna/spf v0.9.5/go.mod h1:o6IdTae6QptAbLgx/+ueXSTSpkG+f1cqLemQJSew8sI=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -128,13 +116,12 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
@ -146,41 +133,38 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
|
||||
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
|
||||
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
|
||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
||||
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
||||
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
|
||||
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
|
||||
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/cc/v4 v4.20.0 h1:45Or8mQfbUqJOG9WaxvlFYOAQO0lQ5RvqBcFCXngjxk=
|
||||
modernc.org/cc/v4 v4.20.0/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
|
||||
modernc.org/ccgo/v4 v4.16.0 h1:ofwORa6vx2FMm0916/CkZjpFPSR70VwTjUCe2Eg5BnA=
|
||||
modernc.org/ccgo/v4 v4.16.0/go.mod h1:dkNyWIjFrVIZ68DTo36vHK+6/ShBn4ysU61So6PIqCI=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
|
||||
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
|
||||
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b h1:BnN1t+pb1cy61zbvSUV7SeI0PwosMhlAEi/vBY4qxp8=
|
||||
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||
modernc.org/libc v1.49.3 h1:j2MRCRdwJI2ls/sGbeSk0t2bypOG/uvPZUsGQFDulqg=
|
||||
modernc.org/libc v1.49.3/go.mod h1:yMZuGkn7pXbKfoT/M35gFJOAEdSKdxL0q64sF7KqCDo=
|
||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
|
||||
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.24.0 h1:EsClRIWHGhLTCX44p+Ri/JLD+vFGo0QGjasg2/F9TlI=
|
||||
modernc.org/sqlite v1.24.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
|
||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
|
||||
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
|
||||
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
|
||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
|
||||
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=
|
||||
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
|
||||
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
|
||||
modernc.org/sqlite v1.29.6 h1:0lOXGrycJPptfHDuohfYgNqoe4hu+gYuN/pKgY5XjS4=
|
||||
modernc.org/sqlite v1.29.6/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U=
|
||||
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
|
||||
@ -26,6 +26,29 @@ type HookSender struct {
|
||||
socket string
|
||||
}
|
||||
|
||||
func (h *HookSender) ReceiveSaveAfter(ctx *context.Context, email *parsemail.Email) {
|
||||
log.WithContext(ctx).Debugf("[%s]Plugin ReceiveSaveAfter Start", h.name)
|
||||
|
||||
dto := framework.HookDTO{
|
||||
Ctx: ctx,
|
||||
Email: email,
|
||||
}
|
||||
body, _ := json.Marshal(dto)
|
||||
|
||||
ret, err := h.httpc.Post("http://plugin/ReceiveSaveAfter", "application/json", strings.NewReader(string(body)))
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Errorf("[%s] Error! %v", h.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
body, _ = io.ReadAll(ret.Body)
|
||||
json.Unmarshal(body, &dto)
|
||||
|
||||
ctx = dto.Ctx
|
||||
email = dto.Email
|
||||
log.WithContext(ctx).Debugf("[%s]Plugin ReceiveSaveAfter End", h.name)
|
||||
}
|
||||
|
||||
func (h *HookSender) SendBefore(ctx *context.Context, email *parsemail.Email) {
|
||||
log.WithContext(ctx).Debugf("[%s]Plugin SendBefore Start", h.name)
|
||||
|
||||
|
||||
@ -22,8 +22,10 @@ type EmailHook interface {
|
||||
SendAfter(ctx *context.Context, email *parsemail.Email, err map[string]error)
|
||||
// ReceiveParseBefore 接收到邮件,解析之前的原始数据
|
||||
ReceiveParseBefore(ctx *context.Context, email *[]byte)
|
||||
// ReceiveParseAfter 接收到邮件,解析之后的结构化数据
|
||||
// ReceiveParseAfter 接收到邮件,解析之后的结构化数据 (收信规则前,写数据库前执行)
|
||||
ReceiveParseAfter(ctx *context.Context, email *parsemail.Email)
|
||||
// ReceiveSaveAfter 邮件落库以后执行(收信规则后执行)
|
||||
ReceiveSaveAfter(ctx *context.Context, email *parsemail.Email)
|
||||
}
|
||||
|
||||
// HookDTO PMail 主程序和插件通信的结构体
|
||||
@ -142,6 +144,20 @@ func (p *Plugin) Run() {
|
||||
writer.Write(body)
|
||||
log.Debugf("[%s] ReceiveParseAfter End", p.name)
|
||||
})
|
||||
mux.HandleFunc("/ReceiveSaveAfter", func(writer http.ResponseWriter, request *http.Request) {
|
||||
log.Debugf("[%s] ReceiveSaveAfter Start", p.name)
|
||||
var hookDTO HookDTO
|
||||
body, _ := io.ReadAll(request.Body)
|
||||
err := json.Unmarshal(body, &hookDTO)
|
||||
if err != nil {
|
||||
log.Errorf("params error %+v", err)
|
||||
return
|
||||
}
|
||||
p.hook.ReceiveSaveAfter(hookDTO.Ctx, hookDTO.Email)
|
||||
body, _ = json.Marshal(hookDTO)
|
||||
writer.Write(body)
|
||||
log.Debugf("[%s] ReceiveSaveAfter End", p.name)
|
||||
})
|
||||
|
||||
server := http.Server{
|
||||
ReadTimeout: 5 * time.Second,
|
||||
|
||||
@ -21,6 +21,17 @@ type TelegramPushHook struct {
|
||||
webDomain string
|
||||
}
|
||||
|
||||
func (w *TelegramPushHook) ReceiveSaveAfter(ctx *context.Context, email *parsemail.Email) {
|
||||
if w.chatId == "" || w.botToken == "" {
|
||||
return
|
||||
}
|
||||
// 被标记为已读,或者是已删除,或是垃圾邮件 就不处理了
|
||||
if email.IsRead == 1 || email.Status == 3 || email.MessageId <= 0 {
|
||||
return
|
||||
}
|
||||
w.sendUserMsg(nil, email)
|
||||
}
|
||||
|
||||
func (w *TelegramPushHook) SendBefore(ctx *context.Context, email *parsemail.Email) {
|
||||
|
||||
}
|
||||
@ -33,13 +44,7 @@ func (w *TelegramPushHook) ReceiveParseBefore(ctx *context.Context, email *[]byt
|
||||
|
||||
}
|
||||
|
||||
func (w *TelegramPushHook) ReceiveParseAfter(ctx *context.Context, email *parsemail.Email) {
|
||||
if w.chatId == "" || w.botToken == "" {
|
||||
return
|
||||
}
|
||||
|
||||
w.sendUserMsg(nil, email)
|
||||
}
|
||||
func (w *TelegramPushHook) ReceiveParseAfter(ctx *context.Context, email *parsemail.Email) {}
|
||||
|
||||
type SendMessageRequest struct {
|
||||
ChatID string `json:"chat_id"`
|
||||
|
||||
@ -3,14 +3,13 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
"os"
|
||||
"pmail/config"
|
||||
"pmail/dto/parsemail"
|
||||
"pmail/hooks/framework"
|
||||
"pmail/utils/context"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type WebPushHook struct {
|
||||
@ -18,28 +17,7 @@ type WebPushHook struct {
|
||||
token string
|
||||
}
|
||||
|
||||
// EmailData 用于存储解析后的邮件数据
|
||||
type EmailData struct {
|
||||
From string `json:"from"`
|
||||
To []string `json:"to"`
|
||||
Subject string `json:"subject"`
|
||||
Body string `json:"body"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func (w *WebPushHook) SendBefore(ctx *context.Context, email *parsemail.Email) {
|
||||
|
||||
}
|
||||
|
||||
func (w *WebPushHook) SendAfter(ctx *context.Context, email *parsemail.Email, err map[string]error) {
|
||||
|
||||
}
|
||||
|
||||
func (w *WebPushHook) ReceiveParseBefore(ctx *context.Context, email *[]byte) {
|
||||
|
||||
}
|
||||
|
||||
func (w *WebPushHook) ReceiveParseAfter(ctx *context.Context, email *parsemail.Email) {
|
||||
func (w *WebPushHook) ReceiveSaveAfter(ctx *context.Context, email *parsemail.Email) {
|
||||
if w.url == "" {
|
||||
return
|
||||
}
|
||||
@ -78,6 +56,29 @@ func (w *WebPushHook) ReceiveParseAfter(ctx *context.Context, email *parsemail.E
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
// EmailData 用于存储解析后的邮件数据
|
||||
type EmailData struct {
|
||||
From string `json:"from"`
|
||||
To []string `json:"to"`
|
||||
Subject string `json:"subject"`
|
||||
Body string `json:"body"`
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func (w *WebPushHook) SendBefore(ctx *context.Context, email *parsemail.Email) {
|
||||
|
||||
}
|
||||
|
||||
func (w *WebPushHook) SendAfter(ctx *context.Context, email *parsemail.Email, err map[string]error) {
|
||||
|
||||
}
|
||||
|
||||
func (w *WebPushHook) ReceiveParseBefore(ctx *context.Context, email *[]byte) {
|
||||
|
||||
}
|
||||
|
||||
func (w *WebPushHook) ReceiveParseAfter(ctx *context.Context, email *parsemail.Email) {}
|
||||
|
||||
type Config struct {
|
||||
WebPushUrl string `json:"webPushUrl"`
|
||||
WebPushToken string `json:"webPushToken"`
|
||||
|
||||
@ -31,6 +31,25 @@ type WeChatPushHook struct {
|
||||
mainConfig *config.Config
|
||||
}
|
||||
|
||||
func (w *WeChatPushHook) ReceiveSaveAfter(ctx *context.Context, email *parsemail.Email) {
|
||||
if w.appId == "" || w.secret == "" || w.pushUser == "" {
|
||||
return
|
||||
}
|
||||
|
||||
// 被标记为已读,或者是已删除,或是垃圾邮件 就不处理了
|
||||
if email.IsRead == 1 || email.Status == 3 || email.MessageId <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
content := string(email.Text)
|
||||
|
||||
if content == "" {
|
||||
content = email.Subject
|
||||
}
|
||||
|
||||
w.sendUserMsg(nil, w.pushUser, content)
|
||||
}
|
||||
|
||||
func (w *WeChatPushHook) SendBefore(ctx *context.Context, email *parsemail.Email) {
|
||||
|
||||
}
|
||||
@ -43,19 +62,7 @@ func (w *WeChatPushHook) ReceiveParseBefore(ctx *context.Context, email *[]byte)
|
||||
|
||||
}
|
||||
|
||||
func (w *WeChatPushHook) ReceiveParseAfter(ctx *context.Context, email *parsemail.Email) {
|
||||
if w.appId == "" || w.secret == "" || w.pushUser == "" {
|
||||
return
|
||||
}
|
||||
|
||||
content := string(email.Text)
|
||||
|
||||
if content == "" {
|
||||
content = email.Subject
|
||||
}
|
||||
|
||||
w.sendUserMsg(nil, w.pushUser, content)
|
||||
}
|
||||
func (w *WeChatPushHook) ReceiveParseAfter(ctx *context.Context, email *parsemail.Email) {}
|
||||
|
||||
func (w *WeChatPushHook) getWxAccessToken() string {
|
||||
if w.tokenExpires > time.Now().Unix() {
|
||||
|
||||
@ -178,6 +178,7 @@ func (a action) Stat(session *gopop.Session) (msgNum, msgSize int64, err error)
|
||||
return si.Num, si.Size, nil
|
||||
}
|
||||
|
||||
// Uidl 查询某封邮件的唯一标志符
|
||||
func (a action) Uidl(session *gopop.Session, msg string) ([]gopop.UidlItem, error) {
|
||||
log.WithContext(session.Ctx).Debugf("POP3 CMD: UIDL ,Args:%s", msg)
|
||||
|
||||
@ -196,7 +197,7 @@ func (a action) Uidl(session *gopop.Session, msg string) ([]gopop.UidlItem, erro
|
||||
var err error
|
||||
var ssql string
|
||||
|
||||
ssql = db.WithContext(session.Ctx.(*context.Context), "SELECT id FROM email")
|
||||
ssql = db.WithContext(session.Ctx.(*context.Context), "SELECT id FROM email where type = 0")
|
||||
err = db.Instance.Select(&res, ssql)
|
||||
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
@ -319,7 +320,7 @@ func (a action) Quit(session *gopop.Session) error {
|
||||
log.WithContext(session.Ctx).Debugf("POP3 CMD: QUIT ")
|
||||
if len(session.DeleteIds) > 0 {
|
||||
|
||||
_, err := db.Instance.Exec(db.WithContext(session.Ctx.(*context.Context), "DELETE FROM email WHERE id in ?"), session.DeleteIds)
|
||||
_, err := db.Instance.Exec(db.WithContext(session.Ctx.(*context.Context), "UPDATE email SET status=3 WHERE id in ?"), session.DeleteIds)
|
||||
if err != nil {
|
||||
log.WithContext(session.Ctx.(*context.Context)).Errorf("%+v", err)
|
||||
}
|
||||
|
||||
53
server/pop3_server/action_test.go
Normal file
53
server/pop3_server/action_test.go
Normal file
@ -0,0 +1,53 @@
|
||||
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)
|
||||
}
|
||||
@ -65,8 +65,14 @@ func DoRule(ctx *context.Context, rule *dto.Rule, email *parsemail.Email) {
|
||||
switch rule.Action {
|
||||
case dto.READ:
|
||||
email.IsRead = 1
|
||||
if email.MessageId > 0 {
|
||||
db.Instance.Exec(db.WithContext(ctx, "update email set is_read=1 where id =?"), email.MessageId)
|
||||
}
|
||||
case dto.DELETE:
|
||||
email.Status = 3
|
||||
if email.MessageId > 0 {
|
||||
db.Instance.Exec(db.WithContext(ctx, "update email set status=3 where id =?"), email.MessageId)
|
||||
}
|
||||
case dto.FORWARD:
|
||||
if strings.Contains(rule.Params, config.Instance.Domain) {
|
||||
log.WithContext(ctx).Errorf("Forward Error! loop forwarding!")
|
||||
@ -78,5 +84,9 @@ func DoRule(ctx *context.Context, rule *dto.Rule, email *parsemail.Email) {
|
||||
}
|
||||
case dto.MOVE:
|
||||
email.GroupId = cast.ToInt(rule.Params)
|
||||
if email.MessageId > 0 {
|
||||
db.Instance.Exec(db.WithContext(ctx, "update email set group_id=? where id =?"), email.GroupId, email.MessageId)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -123,14 +123,30 @@ func (s *Session) Data(r io.Reader) error {
|
||||
|
||||
saveEmail(ctx, email, 0, SPFStatus, dkimStatus)
|
||||
|
||||
log.WithContext(ctx).Debugf("开始执行邮件规则!")
|
||||
// 执行邮件规则
|
||||
rs := rule.GetAllRules(ctx)
|
||||
for _, r := range rs {
|
||||
if rule.MatchRule(ctx, r, email) {
|
||||
rule.DoRule(ctx, r, email)
|
||||
if email.MessageId > 0 {
|
||||
log.WithContext(ctx).Debugf("开始执行邮件规则!")
|
||||
// 执行邮件规则
|
||||
rs := rule.GetAllRules(ctx)
|
||||
for _, r := range rs {
|
||||
if rule.MatchRule(ctx, r, email) {
|
||||
rule.DoRule(ctx, r, email)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.WithContext(ctx).Debugf("开始执行插件ReceiveSaveAfter!")
|
||||
as3 := async.New(ctx)
|
||||
for _, hook := range hooks.HookList {
|
||||
if hook == nil {
|
||||
continue
|
||||
}
|
||||
as3.WaitProcess(func(hk any) {
|
||||
hk.(framework.EmailHook).ReceiveSaveAfter(ctx, email)
|
||||
}, hook)
|
||||
}
|
||||
as3.Wait()
|
||||
log.WithContext(ctx).Debugf("开始执行插件ReceiveSaveAfter!End")
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -186,7 +202,7 @@ func saveEmail(ctx *context.Context, email *parsemail.Email, emailType int, SPFS
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.WithContext(ctx).Println("mysql insert error:", err.Error())
|
||||
log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())
|
||||
}
|
||||
insertId, _ := res.LastInsertId()
|
||||
if insertId > 0 {
|
||||
|
||||
@ -401,11 +401,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)))
|
||||
@ -509,3 +505,41 @@ Content-Type: text/html
|
||||
|
||||
s.Data(bytes.NewReader([]byte(moveEmail)))
|
||||
}
|
||||
|
||||
func TestQAEmailForward(t *testing.T) {
|
||||
testInit()
|
||||
data := `Mime-Version: 1.0
|
||||
X-QQ-MIME: TCMime 1.0 by Tencent
|
||||
X-Mailer: QQMail 2.x
|
||||
X-QQ-Mailer: QQMail 2.x
|
||||
Message-ID: tencent_D82739970C66D2BFBA23F4A3@qq.com
|
||||
Subject: =?UTF-8?B?5rWL6K+V5Y+R6YCB?=
|
||||
Date: Wed, 10 Apr 2024 11:11:12 +0800 (GMT+08:00)
|
||||
From: =?UTF-8?B?YWRtaW5AamlubnJyeS5jb20=?=<admin@jinnrry.com>
|
||||
To: =?UTF-8?B??=<test@jinnrry.com>
|
||||
Content-Type: multipart/alternative;
|
||||
boundary="----=_Part_174_107154538.1712718674768"
|
||||
|
||||
------=_Part_174_107154538.1712718674768
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
|
||||
------=_Part_174_107154538.1712718674768
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
PGRpdj7ov5nph4zmmK/lhoXlrrk8L2Rpdj48ZGl2PjwhLS1lbXB0eXNpZ24tLT48L2Rpdj4=
|
||||
------=_Part_174_107154538.1712718674768--`
|
||||
|
||||
s := Session{
|
||||
RemoteAddress: net.TCPAddrFromAddrPort(netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), 25)),
|
||||
Ctx: &context.Context{
|
||||
UserID: 1,
|
||||
UserName: "a",
|
||||
UserAccount: "a",
|
||||
},
|
||||
}
|
||||
|
||||
s.Data(bytes.NewReader([]byte(data)))
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package smtp_server
|
||||
import (
|
||||
"crypto/tls"
|
||||
"database/sql"
|
||||
"github.com/emersion/go-sasl"
|
||||
"github.com/emersion/go-smtp"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"net"
|
||||
@ -42,6 +43,30 @@ type Session struct {
|
||||
Ctx *context.Context
|
||||
}
|
||||
|
||||
// AuthMechanisms returns a slice of available auth mechanisms
|
||||
// supported in this example.
|
||||
func (s *Session) AuthMechanisms() []string {
|
||||
return []string{sasl.Plain, sasl.Login}
|
||||
}
|
||||
|
||||
// Auth is the handler for supported authenticators.
|
||||
func (s *Session) Auth(mech string) (sasl.Server, error) {
|
||||
log.WithContext(s.Ctx).Debugf("Auth :%s", mech)
|
||||
if mech == sasl.Plain {
|
||||
return sasl.NewPlainServer(func(identity, username, password string) error {
|
||||
return s.AuthPlain(username, password)
|
||||
}), nil
|
||||
}
|
||||
|
||||
if mech == sasl.Login {
|
||||
return sasl.NewLoginServer(func(username, password string) error {
|
||||
return s.AuthPlain(username, password)
|
||||
}), nil
|
||||
}
|
||||
|
||||
return nil, errors.New("Auth Not Supported")
|
||||
}
|
||||
|
||||
func (s *Session) AuthPlain(username, pwd string) error {
|
||||
log.WithContext(s.Ctx).Debugf("Auth %s %s", username, pwd)
|
||||
|
||||
@ -105,7 +130,6 @@ func StartWithTLS() {
|
||||
instanceTls.Addr = ":465"
|
||||
instanceTls.Domain = config.Instance.Domain
|
||||
instanceTls.ReadTimeout = 10 * time.Second
|
||||
instanceTls.AuthDisabled = false
|
||||
instanceTls.WriteTimeout = 10 * time.Second
|
||||
instanceTls.MaxMessageBytes = 1024 * 1024
|
||||
instanceTls.MaxRecipients = 50
|
||||
@ -134,7 +158,6 @@ func Start() {
|
||||
instance.Addr = ":25"
|
||||
instance.Domain = config.Instance.Domain
|
||||
instance.ReadTimeout = 10 * time.Second
|
||||
instance.AuthDisabled = false
|
||||
instance.WriteTimeout = 10 * time.Second
|
||||
instance.MaxMessageBytes = 1024 * 1024
|
||||
instance.MaxRecipients = 50
|
||||
|
||||
15
server/smtp_server/smtp_test/sendEmailTest.py
Normal file
15
server/smtp_server/smtp_test/sendEmailTest.py
Normal file
@ -0,0 +1,15 @@
|
||||
from email.mime.text import MIMEText
|
||||
import smtplib
|
||||
msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
|
||||
|
||||
|
||||
from_addr = "admin@domain.com"
|
||||
password = "admin"
|
||||
to_addr = "admin@domain.com"
|
||||
smtp_server = "127.0.0.1"
|
||||
|
||||
server = smtplib.SMTP(smtp_server, 25)
|
||||
server.starttls()
|
||||
server.login(from_addr, password)
|
||||
server.sendmail(from_addr, [to_addr], msg.as_string())
|
||||
server.quit()
|
||||
Loading…
Reference in New Issue
Block a user