From 096b4b8fede68f0c2e9542d8899f3c8687112f03 Mon Sep 17 00:00:00 2001 From: jinnrry Date: Sat, 13 Apr 2024 08:55:03 +0800 Subject: [PATCH] v2.4.3 (#5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 插件迭代、收信规则bug修复 修复邮箱地址解析错误 修改pop删除命令为软删除 升级所有依赖 --- Dockerfile | 23 +-- DockerfileGithubAction | 2 + README.md | 9 +- README_CN.md | 8 +- server/config/config.json | 2 +- server/config/config_mysql.json | 10 +- server/dto/parsemail/email.go | 30 ++-- server/dto/parsemail/email_test.go | 16 ++ server/go.mod | 68 ++++--- server/go.sum | 168 ++++++++---------- server/hooks/base.go | 23 +++ server/hooks/framework/framework.go | 18 +- server/hooks/telegram_push/telegram_push.go | 19 +- server/hooks/web_push/web_push.go | 49 ++--- server/hooks/wechat_push/wechat_push.go | 33 ++-- server/pop3_server/action.go | 5 +- server/pop3_server/action_test.go | 53 ++++++ server/services/rule/rule.go | 10 ++ server/smtp_server/read_content.go | 30 +++- server/smtp_server/read_content_test.go | 44 ++++- server/smtp_server/smtp.go | 27 ++- server/smtp_server/smtp_test/sendEmailTest.py | 15 ++ 22 files changed, 431 insertions(+), 231 deletions(-) create mode 100644 server/pop3_server/action_test.go create mode 100644 server/smtp_server/smtp_test/sendEmailTest.py diff --git a/Dockerfile b/Dockerfile index 5710946..8633aab 100644 --- a/Dockerfile +++ b/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 diff --git a/DockerfileGithubAction b/DockerfileGithubAction index ef08d69..4d73fe8 100644 --- a/DockerfileGithubAction +++ b/DockerfileGithubAction @@ -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 diff --git a/README.md b/README.md index c8d1d97..87a4df9 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/README_CN.md b/README_CN.md index 67ede80..5543d85 100644 --- a/README_CN.md +++ b/README_CN.md @@ -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) diff --git a/server/config/config.json b/server/config/config.json index 1400834..54b48a7 100644 --- a/server/config/config.json +++ b/server/config/config.json @@ -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, diff --git a/server/config/config_mysql.json b/server/config/config_mysql.json index c2e7d64..b5eee8f 100644 --- a/server/config/config_mysql.json +++ b/server/config/config_mysql.json @@ -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 } \ No newline at end of file diff --git a/server/dto/parsemail/email.go b/server/dto/parsemail/email.go index 2cac13e..515b850 100644 --- a/server/dto/parsemail/email.go +++ b/server/dto/parsemail/email.go @@ -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 } diff --git a/server/dto/parsemail/email_test.go b/server/dto/parsemail/email_test.go index 3c7c5e5..d33c343 100644 --- a/server/dto/parsemail/email_test.go +++ b/server/dto/parsemail/email_test.go @@ -77,6 +77,22 @@ func Test_buildUser(t *testing.T) { if u.Name != "Jinnrry N" { t.Error("error") } + + u = buildUser("=?UTF-8?B?YWRtaW5AamlubnJyeS5jb20=?=") + if u.EmailAddress != "admin@jinnrry.com" { + t.Error("error") + } + if u.Name != "admin@jinnrry.com" { + t.Error("error") + } + + u = buildUser("\"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) { diff --git a/server/go.mod b/server/go.mod index f084ff0..fc721ba 100644 --- a/server/go.mod +++ b/server/go.mod @@ -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 ) diff --git a/server/go.sum b/server/go.sum index a5bd120..42fe558 100644 --- a/server/go.sum +++ b/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= diff --git a/server/hooks/base.go b/server/hooks/base.go index ae0e4a4..89c209f 100644 --- a/server/hooks/base.go +++ b/server/hooks/base.go @@ -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) diff --git a/server/hooks/framework/framework.go b/server/hooks/framework/framework.go index 044b091..1f5ab2c 100644 --- a/server/hooks/framework/framework.go +++ b/server/hooks/framework/framework.go @@ -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, diff --git a/server/hooks/telegram_push/telegram_push.go b/server/hooks/telegram_push/telegram_push.go index 9049106..89f59a1 100644 --- a/server/hooks/telegram_push/telegram_push.go +++ b/server/hooks/telegram_push/telegram_push.go @@ -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"` diff --git a/server/hooks/web_push/web_push.go b/server/hooks/web_push/web_push.go index 4a092ce..6774bba 100644 --- a/server/hooks/web_push/web_push.go +++ b/server/hooks/web_push/web_push.go @@ -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"` diff --git a/server/hooks/wechat_push/wechat_push.go b/server/hooks/wechat_push/wechat_push.go index ca3639b..d527e39 100644 --- a/server/hooks/wechat_push/wechat_push.go +++ b/server/hooks/wechat_push/wechat_push.go @@ -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() { diff --git a/server/pop3_server/action.go b/server/pop3_server/action.go index d0818e1..03b77a9 100644 --- a/server/pop3_server/action.go +++ b/server/pop3_server/action.go @@ -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) } diff --git a/server/pop3_server/action_test.go b/server/pop3_server/action_test.go new file mode 100644 index 0000000..d5ab972 --- /dev/null +++ b/server/pop3_server/action_test.go @@ -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) +} diff --git a/server/services/rule/rule.go b/server/services/rule/rule.go index 4e8882e..eeb0db4 100644 --- a/server/services/rule/rule.go +++ b/server/services/rule/rule.go @@ -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) + } } + } diff --git a/server/smtp_server/read_content.go b/server/smtp_server/read_content.go index f86393d..b5e1519 100644 --- a/server/smtp_server/read_content.go +++ b/server/smtp_server/read_content.go @@ -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 { diff --git a/server/smtp_server/read_content_test.go b/server/smtp_server/read_content_test.go index 9595747..9582546 100644 --- a/server/smtp_server/read_content_test.go +++ b/server/smtp_server/read_content_test.go @@ -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=?= +To: =?UTF-8?B??= +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))) +} diff --git a/server/smtp_server/smtp.go b/server/smtp_server/smtp.go index 32ad085..7b6b432 100644 --- a/server/smtp_server/smtp.go +++ b/server/smtp_server/smtp.go @@ -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 diff --git a/server/smtp_server/smtp_test/sendEmailTest.py b/server/smtp_server/smtp_test/sendEmailTest.py new file mode 100644 index 0000000..c275c94 --- /dev/null +++ b/server/smtp_server/smtp_test/sendEmailTest.py @@ -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() \ No newline at end of file