1、新增垃圾邮件过滤插件
2、使用使用github.com/dlclark/regexp2替换go原生的正则包
3、修复空数据导致的邮件插入失败
This commit is contained in:
Jinnrry 2024-07-20 10:39:17 +08:00 committed by GitHub
parent 9ffbdf41c3
commit 054336fe9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
78 changed files with 1123 additions and 329 deletions

View File

@ -42,6 +42,7 @@ jobs:
echo "TGFILENAME=telegram_push_${{ matrix.goos }}_${{ matrix.goarch }}" >> ${GITHUB_ENV}
echo "WCFILENAME=wechat_push_${{ matrix.goos }}_${{ matrix.goarch }}" >> ${GITHUB_ENV}
echo "WEBFILENAME=web_push_${{ matrix.goos }}_${{ matrix.goarch }}" >> ${GITHUB_ENV}
echo "SPAMBLOCKFILENAME=spam_block_${{ matrix.goos }}_${{ matrix.goarch }}" >> ${GITHUB_ENV}
echo "ZIPNAME=${{ matrix.goos }}_${{ matrix.goarch }}" >> ${GITHUB_ENV}
- name: Rename Windows File
if: matrix.goos == 'windows'
@ -50,6 +51,7 @@ jobs:
echo "TGFILENAME=telegram_push_${{ matrix.goos }}_${{ matrix.goarch }}.exe" >> ${GITHUB_ENV}
echo "WCFILENAME=wechat_push_${{ matrix.goos }}_${{ matrix.goarch }}.exe" >> ${GITHUB_ENV}
echo "WEBFILENAME=web_push_${{ matrix.goos }}_${{ matrix.goarch }}.exe" >> ${GITHUB_ENV}
echo "SPAMBLOCKFILENAME=spam_block_${{ matrix.goos }}_${{ matrix.goarch }}.exe" >> ${GITHUB_ENV}
- name: FE Build
run: cd fe && yarn && yarn build
- name: BE Build
@ -59,6 +61,7 @@ jobs:
go build -ldflags "-s -w" -o ${{ env.TGFILENAME }} hooks/telegram_push/telegram_push.go
go build -ldflags "-s -w" -o ${{ env.WEBFILENAME }} hooks/web_push/web_push.go
go build -ldflags "-s -w" -o ${{ env.WCFILENAME }} hooks/wechat_push/wechat_push.go
go build -ldflags "-s -w" -o ${{ env.SPAMBLOCKFILENAME }} hooks/spam_blcok/spam_blcok.go
ls -alh
- name: Zip
run: |
@ -67,6 +70,7 @@ jobs:
mv ${{ env.TGFILENAME }} plugins/
mv ${{ env.WEBFILENAME }} plugins/
mv ${{ env.WCFILENAME }} plugins/
mv ${{ env.SPAMBLOCKFILENAME }} plugins/
zip -r ${{ env.ZIPNAME }}.zip ${{ env.FILENAME }} plugins
ls
- name: Upload files to Artifacts

View File

@ -16,6 +16,7 @@ RUN cd /work/server && go build -ldflags "-s -w -X 'main.version=${VERSION}' -X
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
RUN cd /work/server/hooks/spam_blcok && go build -ldflags "-s -w" -o output/spam_blcok spam_blcok.go
FROM alpine
@ -34,6 +35,7 @@ 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/
COPY --from=serverbuild /work/server/hooks/spam_blcok/output/* ./plugins/
EXPOSE 25 80 110 443 465 995

View File

@ -10,6 +10,7 @@ RUN go build -ldflags "-s -w -X 'main.version=${VERSION}' -X 'main.goVersion=$(g
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/hooks/spam_blcok && go build -ldflags "-s -w" -o output/spam_blcok spam_blcok.go
FROM alpine
@ -28,6 +29,7 @@ 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/hooks/spam_blcok/output/* ./plugins/
EXPOSE 25 80 110 443 465 995

View File

@ -33,6 +33,14 @@ wechat_push:
cd server/hooks/wechat_push && CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -o output/wechat_push_mac_amd64 wechat_push.go
cd server/hooks/wechat_push && CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w" -o output/wechat_push_mac_arm64 wechat_push.go
spam_block:
cd server/hooks/spam_block && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -o output/spam_block_linux_amd64 spam_block.go
cd server/hooks/spam_block && CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -o output/spam_block_windows_amd64.exe spam_block.go
cd server/hooks/spam_block && CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -o output/spam_block_mac_amd64 spam_block.go
cd server/hooks/spam_block && CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w" -o output/spam_block_mac_arm64 spam_block.go
plugin: telegram_push wechat_push web_push

View File

@ -2,11 +2,11 @@ package controllers
import (
"fmt"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/services/attachments"
"github.com/Jinnrry/pmail/utils/context"
"github.com/spf13/cast"
"net/http"
"pmail/dto/response"
"pmail/services/attachments"
"pmail/utils/context"
"strings"
)

View File

@ -1,8 +1,8 @@
package controllers
import (
"github.com/Jinnrry/pmail/utils/context"
"net/http"
"pmail/utils/context"
)
type HandlerFunc func(*context.Context, http.ResponseWriter, *http.Request)

View File

@ -2,12 +2,12 @@ package email
import (
"encoding/json"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/services/del_email"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"pmail/dto/response"
"pmail/services/del_email"
"pmail/utils/context"
)
type emailDeleteRequest struct {

View File

@ -2,12 +2,12 @@ package email
import (
"encoding/json"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/services/detail"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"pmail/dto/response"
"pmail/services/detail"
"pmail/utils/context"
)
type emailDetailRequest struct {

View File

@ -2,15 +2,15 @@ package email
import (
"encoding/json"
"github.com/Jinnrry/pmail/dto"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/services/list"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"io"
"math"
"net/http"
"pmail/dto"
"pmail/dto/response"
"pmail/services/list"
"pmail/utils/context"
)
type emailListResponse struct {

View File

@ -2,12 +2,12 @@ package email
import (
"encoding/json"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/services/group"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"pmail/dto/response"
"pmail/services/group"
"pmail/utils/context"
)
type moveRequest struct {

View File

@ -2,12 +2,12 @@ package email
import (
"encoding/json"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/services/detail"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"pmail/dto/response"
"pmail/services/detail"
"pmail/utils/context"
)
type markReadRequest struct {

View File

@ -4,22 +4,22 @@ import (
"database/sql"
"encoding/base64"
"encoding/json"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/hooks"
"github.com/Jinnrry/pmail/hooks/framework"
"github.com/Jinnrry/pmail/i18n"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/async"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/send"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"io"
"net/http"
"pmail/config"
"pmail/db"
"pmail/dto/parsemail"
"pmail/dto/response"
"pmail/hooks"
"pmail/hooks/framework"
"pmail/i18n"
"pmail/models"
"pmail/utils/array"
"pmail/utils/async"
"pmail/utils/context"
"pmail/utils/send"
"strings"
"time"
)
@ -168,30 +168,31 @@ func Send(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
log.WithContext(ctx).Debugf("插件执行--SendBefore End")
modelEmail := models.Email{
Type: 1,
Subject: e.Subject,
ReplyTo: json2string(e.ReplyTo),
FromName: e.From.Name,
FromAddress: e.From.EmailAddress,
To: json2string(e.To),
Bcc: json2string(e.Bcc),
Cc: json2string(e.Cc),
Text: sql.NullString{String: string(e.Text), Valid: true},
Html: sql.NullString{String: string(e.HTML), Valid: true},
Sender: json2string(e.Sender),
Attachments: json2string(e.Attachments),
SPFCheck: 1,
DKIMCheck: 1,
SendUserID: ctx.UserID,
SendDate: time.Now(),
Status: 1,
CreateTime: time.Now(),
Type: 1,
Subject: e.Subject,
ReplyTo: json2string(e.ReplyTo),
FromName: e.From.Name,
FromAddress: e.From.EmailAddress,
To: json2string(e.To),
Bcc: json2string(e.Bcc),
Cc: json2string(e.Cc),
Text: sql.NullString{String: string(e.Text), Valid: true},
Html: sql.NullString{String: string(e.HTML), Valid: true},
Sender: json2string(e.Sender),
Attachments: json2string(e.Attachments),
SPFCheck: 1,
DKIMCheck: 1,
SendUserID: ctx.UserID,
SendDate: time.Now(),
CronSendTime: time.Now(),
Status: 1,
CreateTime: time.Now(),
}
_, err = db.Instance.Insert(&modelEmail)
if err != nil || modelEmail.Id <= 0 {
log.Println("mysql insert error:", err.Error())
log.Println("insert error:", err.Error())
response.NewErrorResponse(response.ServerError, i18n.GetText(ctx.Lang, "send_fail"), err.Error()).FPrint(w)
return
}

View File

@ -2,17 +2,17 @@ package controllers
import (
"encoding/json"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/i18n"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/services/group"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"pmail/db"
"pmail/dto"
"pmail/dto/response"
"pmail/i18n"
"pmail/models"
"pmail/services/group"
"pmail/utils/array"
"pmail/utils/context"
)
func GetUserGroupList(ctx *context.Context, w http.ResponseWriter, req *http.Request) {

View File

@ -1,8 +1,8 @@
package controllers
import (
"github.com/Jinnrry/pmail/config"
"net/http"
"pmail/config"
)
func Interceptor(w http.ResponseWriter, r *http.Request) {

View File

@ -3,19 +3,19 @@ package controllers
import (
"database/sql"
"encoding/json"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/i18n"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/session"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
"github.com/Jinnrry/pmail/utils/password"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"pmail/config"
"pmail/db"
"pmail/dto/response"
"pmail/i18n"
"pmail/models"
"pmail/session"
"pmail/utils/array"
"pmail/utils/context"
"pmail/utils/errors"
"pmail/utils/password"
)
type loginRequest struct {

View File

@ -1,8 +1,8 @@
package controllers
import (
"github.com/Jinnrry/pmail/dto/response"
"net/http"
"pmail/dto/response"
)
func Ping(w http.ResponseWriter, req *http.Request) {

View File

@ -2,19 +2,19 @@ package controllers
import (
"encoding/json"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/i18n"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/services/rule"
"github.com/Jinnrry/pmail/utils/address"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"pmail/db"
"pmail/dto"
"pmail/dto/response"
"pmail/i18n"
"pmail/models"
"pmail/services/rule"
"pmail/utils/address"
"pmail/utils/array"
"pmail/utils/context"
"pmail/utils/errors"
)
func GetRule(ctx *context.Context, w http.ResponseWriter, req *http.Request) {

View File

@ -2,14 +2,14 @@ package controllers
import (
"encoding/json"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/i18n"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/password"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"pmail/db"
"pmail/dto/response"
"pmail/i18n"
"pmail/utils/context"
"pmail/utils/password"
)
type modifyPasswordRequest struct {

View File

@ -2,16 +2,16 @@ package controllers
import (
"encoding/json"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/services/setup"
"github.com/Jinnrry/pmail/services/setup/ssl"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"io"
"net/http"
"os"
"pmail/config"
"pmail/dto/response"
"pmail/services/setup"
"pmail/services/setup/ssl"
"pmail/utils/context"
"strings"
)

View File

@ -2,18 +2,18 @@ package controllers
import (
"encoding/json"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/password"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"io"
"math"
"net/http"
"pmail/config"
"pmail/db"
"pmail/dto/response"
"pmail/models"
"pmail/utils/array"
"pmail/utils/context"
"pmail/utils/password"
)
type userCreateRequest struct {

View File

@ -1,10 +1,10 @@
package cron_server
import (
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/services/setup/ssl"
"github.com/Jinnrry/pmail/signal"
log "github.com/sirupsen/logrus"
"pmail/config"
"pmail/services/setup/ssl"
"pmail/signal"
"time"
)

View File

@ -2,14 +2,14 @@ package db
import (
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
log "github.com/sirupsen/logrus"
_ "modernc.org/sqlite"
"pmail/config"
"pmail/models"
"pmail/utils/context"
"pmail/utils/errors"
"xorm.io/xorm"
)

View File

@ -6,13 +6,13 @@ import (
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/utils/consts"
"github.com/emersion/go-msgauth/dkim"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ed25519"
"io"
"os"
"pmail/config"
"pmail/utils/consts"
"strings"
)

View File

@ -3,14 +3,14 @@ package parsemail
import (
"bytes"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/utils/context"
"github.com/emersion/go-message"
_ "github.com/emersion/go-message/charset"
"github.com/emersion/go-message/mail"
log "github.com/sirupsen/logrus"
"io"
"net/textproto"
"pmail/config"
"pmail/utils/context"
"regexp"
"strings"
"time"

View File

@ -1,6 +1,6 @@
package response
import "pmail/models"
import "github.com/Jinnrry/pmail/models"
type EmailResponseData struct {
models.Email `xorm:"extends"`

View File

@ -2,7 +2,7 @@ package dto
import (
"encoding/json"
"pmail/models"
"github.com/Jinnrry/pmail/models"
)
type RuleType int

View File

@ -1,4 +1,4 @@
module pmail
module github.com/Jinnrry/pmail
go 1.22.0
@ -8,6 +8,7 @@ require (
github.com/alexedwards/scs/postgresstore 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/dlclark/regexp2 v1.11.2
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

View File

@ -17,6 +17,8 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
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/dlclark/regexp2 v1.11.2 h1:/u628IuisSTwri5/UKloiIsH8+qF2Pu7xEQX+yIKg68=
github.com/dlclark/regexp2 v1.11.2/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
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.18.1 h1:tfTxIoXFSFRwWaZsgnqS1DSZuGpYGzSmCZD8SK3QA2E=
@ -26,8 +28,6 @@ github.com/emersion/go-msgauth v0.6.8/go.mod h1:YDwuyTCUHu9xxmAeVj0eW4INnwB6NNZo
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
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.2 h1:OLDgvZKuofk4em9fT5tFG5j4jE1/hXnX75UMvcrL4AA=
github.com/emersion/go-smtp v0.21.2/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/emersion/go-smtp v0.21.3 h1:7uVwagE8iPYE48WhNsng3RRpCUpFvNl39JGNSIyGVMY=
github.com/emersion/go-smtp v0.21.3/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
@ -37,12 +37,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-acme/lego/v4 v4.17.3 h1:5our7Qdyik0abag40abdmQuytq97iweaNHFMT4pYDnQ=
github.com/go-acme/lego/v4 v4.17.3/go.mod h1:Ol6l04hnmavqVHKYS/ByhXXqE64x8yVYhomha82uAUk=
github.com/go-acme/lego/v4 v4.17.4 h1:h0nePd3ObP6o7kAkndtpTzCw8shOZuWckNYeUQwo36Q=
github.com/go-acme/lego/v4 v4.17.4/go.mod h1:dU94SvPNqimEeb7EVilGGSnS0nU1O5Exir0pQ4QFL4U=
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-jose/go-jose/v4 v4.0.3 h1:o8aphO8Hv6RPmH+GfzVuyf7YXSBibp+8YyHdOoDESGo=
github.com/go-jose/go-jose/v4 v4.0.3/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
@ -89,8 +85,6 @@ github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs=
github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk=
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
github.com/mileusna/spf v0.9.5 h1:P6cmaIBwrhZaP9stXMzGOtxe+gIu65OVbZCmrAv9rgU=
@ -141,16 +135,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -163,8 +153,6 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/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.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -196,8 +184,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956/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.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -217,8 +203,6 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
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.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -242,20 +226,16 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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=
modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk=
modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/ccgo/v4 v4.17.10 h1:6wrtRozgrhCxieCeJh85QsxkX/2FFrT9hdaWPlbn4Zo=
modernc.org/ccgo/v4 v4.17.10/go.mod h1:0NBHgsqTTpm9cA5z2ccErvGZmtntSM9qD2kFAs6pjXM=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y=
modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s=
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.52.1 h1:uau0VoiT5hnR+SpoWekCKbLqm7v6dhRL3hI+NQhgN3M=
modernc.org/libc v1.52.1/go.mod h1:HR4nVzFDSDizP620zcMCgjb1/8xk2lg5p/8yjfGv1IQ=
modernc.org/libc v1.54.4 h1:eDr4WnANZv+aRBKNCDo4khJbaHpxoTNOxeXqpznSZyY=
modernc.org/libc v1.54.4/go.mod h1:CH8KSvv67UxcGCOLizggw3Zi3yT+sUjLWysK/YeUnqk=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
@ -266,8 +246,6 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.30.0 h1:8YhPUs/HTnlEgErn/jSYQTwHN/ex8CjHHjg+K9iG7LM=
modernc.org/sqlite v1.30.0/go.mod h1:cgkTARJ9ugeXSNaLBPK3CqbOe7Ec7ZhWPoMFGldEYEw=
modernc.org/sqlite v1.30.1 h1:YFhPVfu2iIgUf9kuA1CR7iiHdcEEsI2i+yjRYHscyxk=
modernc.org/sqlite v1.30.1/go.mod h1:DUmsiWQDaAvU4abhc/N+djlom/L2o8f7gZ95RCvyoLU=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=

View File

@ -4,22 +4,22 @@ import (
oContext "context"
"encoding/json"
"fmt"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/hooks/framework"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"io"
"net"
"net/http"
"os"
"path/filepath"
"pmail/dto/parsemail"
"pmail/hooks/framework"
"pmail/models"
"pmail/utils/context"
"strings"
"time"
)
// HookList
var HookList []framework.EmailHook
var HookList map[string]framework.EmailHook
type HookSender struct {
httpc http.Client
@ -158,6 +158,7 @@ var processList []*os.Process
// Init 注册hook对象
func Init(serverVersion string) {
HookList = map[string]framework.EmailHook{}
env := os.Environ()
procAttr := &os.ProcAttr{
Env: env,
@ -178,6 +179,8 @@ func Init(serverVersion string) {
os.Remove(socketPath)
//socketPath = "/PMail/server/hooks/spam_block/1555.socket" //debug
log.Infof("[%s] Plugin Load", info.Name())
p, err := os.StartProcess(path, []string{
info.Name(),
@ -195,6 +198,8 @@ func Init(serverVersion string) {
go func() {
stat, err := p.Wait()
log.Errorf("[%s] Plugin Stop. Error:%v Stat:%v", info.Name(), err, stat.String())
delete(HookList, info.Name())
os.Remove(socketPath)
}()
loadSucc := false
@ -209,7 +214,7 @@ func Init(serverVersion string) {
}
}
if loadSucc {
HookList = append(HookList, NewHookSender(socketPath, info.Name(), serverVersion))
HookList[info.Name()] = NewHookSender(socketPath, info.Name(), serverVersion)
log.Infof("[%s] Plugin Load Success!", info.Name())
}

View File

@ -4,15 +4,15 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"io"
"net"
"net/http"
"os"
"path/filepath"
"pmail/dto/parsemail"
"pmail/models"
"pmail/utils/context"
"time"
)
@ -167,7 +167,8 @@ func (p *Plugin) Run() {
Handler: mux,
}
unixListener, err := net.Listen("unix", getExePath()+"/"+os.Args[1])
filePath := getExePath() + "/" + os.Args[1]
unixListener, err := net.Listen("unix", filePath)
if err != nil {
panic(err)
}
@ -178,6 +179,8 @@ func (p *Plugin) Run() {
}
func getExePath() string {
//return "/PMail/server/hooks/spam_block" //debug socket path
ex, err := os.Executable()
if err != nil {
panic(err)

View File

@ -0,0 +1,5 @@
build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o export_linux_amd64 export.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o export_windows_amd64.exe export.go
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o export_mac_amd64 export.go
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -o export_mac_arm64 export.go

View File

@ -0,0 +1,88 @@
# 插件介绍
使用机器学习的方式识别垃圾邮件。模型使用的是RETVec。模型参数约 200k在我1核1G的服务器上单次推理耗时约3秒Mac M1上可达到毫秒级耗时。
# Help
目前Google GMail使用的垃圾邮件识别算法也是RETVec理论上识别效果能够达到GMail同等级别。但是我并没有Google那样大量的训练集。欢迎大家以Pull
Request的形式提交机器学习的各类样本数据。
你可以给testData和trainData这两个文件夹下面的csv文件提交PRCSV文件每行的第一个数字表示数据类型0表示正常邮件1表示广告邮件2表示诈骗邮件。
你可以使用export.go这个脚本导出你全部的邮件数据过滤掉隐私内容并且标记好分类后提交上来。
# 如何运行
1、下载或者自己训练模型
2、使用docker运行tensorflow模型
`docker run -d -p 127.0.0.1:8501:8501 \
-v "{模型文件位置}:/models/emotion_model" \
-e MODEL_NAME=emotion_model tensorflow/serving &`
3、CURL测试模型部署是否成功
> 详细部署说明请参考[tensorflow官方](https://www.tensorflow.org/tfx/guide/serving?hl=zh-cn)
```bash
curl -X POST http://localhost:8501/v1/models/emotion_model:predict -d '{
"instances": [
{"token":["各位同事请注意 这里是110请大家立刻把银行卡账号密码回复发给我"]}
]
}'
```
将得到类似输出:
```json
{
"predictions": [
[
0.394376636,
// 正常邮件的得分
0.0055413493,
// 广告邮件的得分
0.633584619
// 诈骗邮件的得分,这里诈骗邮件得分最高,因此最可能为诈骗邮件
]
]
}
```
4、将spam_block插件移动到pmail插件目录
5、在插件位置新建配置文件`spam_block_config.json`内容类似
```json
{
"apiURL": "http://localhost:8501/v1/models/emotion_model:predict",
"apiTimeout": 3000
}
```
apiURL表示模型api访问地址如果你是使用Docker部署PMail和tensorflow/serving容器需要设置为相同网络才能通信并且需要把localhost替换为tensorflow/serving的容器名称
# 模型效果
trec06c数据集
loss: 0.0187 - acc: 0.9948 - val_loss: 0.0047 - val_acc: 0.9993
# 训练模型
`python train.py`
# 测试模型
`python test.py`
# trec06c 数据集
[trec06c_format.py](trec06c_format.py)
脚本用于整理trec06c数据集将其转化为训练所需的数据格式。由于数据集版权限制如有需要请前往[这里](https://plg.uwaterloo.ca/~gvcormac/treccorpus06/about.html)
自行下载,本项目中不直接引入数据集内容。
# 致谢
Tanks For [google-research/retvec](https://github.com/google-research/retvec)

View File

@ -0,0 +1,44 @@
package main
import (
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/hooks/spam_block/tools"
"github.com/Jinnrry/pmail/models"
"os"
)
func main() {
config.Init()
err := db.Init("test")
if err != nil {
panic(err)
}
fmt.Println(config.Instance.DbDSN)
fmt.Println("文件第一列是分类0表示正常邮件1表示垃圾邮件2表示诈骗邮件")
var start int
file, err := os.OpenFile("data.csv", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0777)
if err != nil {
fmt.Println(err)
}
defer file.Close()
for {
var emails []models.Email
db.Instance.Table(&models.Email{}).Where("id > ?", start).OrderBy("id").Find(&emails)
if len(emails) == 0 {
break
}
for _, email := range emails {
start = email.Id
_, err = file.WriteString(fmt.Sprintf("0 \t%s %s\n", email.Subject, tools.Trim(tools.TrimHtml(email.Html.String))))
if err != nil {
fmt.Println(err)
}
//fmt.Printf("0 \t%s %s\n", email.Subject, trim(trimHtml(email.Html.String)))
}
}
}

View File

@ -0,0 +1,4 @@
datasets==2.20.0
numpy==1.20.3
retvec==1.0.1
tensorflow==2.8.4

View File

@ -0,0 +1,157 @@
package main
import (
"encoding/json"
"fmt"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/hooks/framework"
"github.com/Jinnrry/pmail/hooks/spam_block/tools"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"os"
"strings"
"time"
)
type SpamBlock struct {
cfg SpamBlockConfig
hc *http.Client
}
func (s SpamBlock) SendBefore(ctx *context.Context, email *parsemail.Email) {
}
func (s SpamBlock) SendAfter(ctx *context.Context, email *parsemail.Email, err map[string]error) {
}
func (s SpamBlock) ReceiveParseBefore(ctx *context.Context, email *[]byte) {
}
type ModelResponse struct {
Predictions [][]float64 `json:"predictions"`
}
type ApiRequest struct {
Instances []InstanceItem `json:"instances"`
}
type InstanceItem struct {
Token []string `json:"token"`
}
func (s SpamBlock) ReceiveParseAfter(ctx *context.Context, email *parsemail.Email) {
reqData := ApiRequest{
Instances: []InstanceItem{
{
Token: []string{
fmt.Sprintf("%s %s", email.Subject, tools.Trim(tools.TrimHtml(string(email.HTML)))),
},
},
},
}
str, _ := json.Marshal(reqData)
resp, err := s.hc.Post(s.cfg.ApiURL, "application/json", strings.NewReader(string(str)))
if err != nil {
log.Errorf("API Error: %v", err)
return
}
body, _ := io.ReadAll(resp.Body)
modelResponse := ModelResponse{}
err = json.Unmarshal(body, &modelResponse)
if err != nil {
log.WithContext(ctx).Errorf("API Error: %v", err)
return
}
if len(modelResponse.Predictions) == 0 {
log.WithContext(ctx).Errorf("API Response Error: %v", string(body))
return
}
classes := modelResponse.Predictions[0]
if len(classes) != 3 {
return
}
var maxScore float64
var maxClass int
for i, score := range classes {
if score > maxScore {
maxScore = score
maxClass = i
}
}
switch maxClass {
case 0:
log.WithContext(ctx).Infof("[Spam Check Result: Normal] %s", email.Subject)
case 1:
log.WithContext(ctx).Infof("[Spam Check Result: Spam ] %s", email.Subject)
case 2:
log.WithContext(ctx).Infof("[Spam Check Result: Blackmail ] %s", email.Subject)
}
if maxClass != 0 {
email.Status = 3
}
}
func (s SpamBlock) ReceiveSaveAfter(ctx *context.Context, email *parsemail.Email, ue []*models.UserEmail) {
}
type SpamBlockConfig struct {
ApiURL string `json:"apiURL"`
ApiTimeout int `json:"apiTimeout"` // 单位毫秒
}
func NewSpamBlockHook() *SpamBlock {
var pluginConfig SpamBlockConfig
if _, err := os.Stat("./plugins/spam_block_config.json"); err == nil {
cfgData, err := os.ReadFile("./plugins/spam_block_config.json")
if err == nil {
json.Unmarshal(cfgData, &pluginConfig)
}
} else {
log.Infof("No Config file found")
return nil
}
log.Infof("Config: %+v", pluginConfig)
if pluginConfig.ApiURL == "" {
pluginConfig.ApiURL = "http://localhost:8501/v1/models/emotion_model:predict"
}
if pluginConfig.ApiTimeout == 0 {
pluginConfig.ApiTimeout = 3000
}
hc := &http.Client{
Timeout: time.Duration(pluginConfig.ApiTimeout) * time.Millisecond,
}
return &SpamBlock{
cfg: pluginConfig,
hc: hc,
}
}
func main() {
log.Infof("SpamBlockPlug Star Success")
instance := NewSpamBlockHook()
if instance == nil {
return
}
framework.CreatePlugin("spam_block", instance).Run()
}

View File

@ -0,0 +1,34 @@
import os
import numpy as np
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '1' # silence TF INFO messages
import tensorflow as tf
save_path = './emotion_model/1'
model = tf.keras.models.load_model(save_path, compile=False)
model.summary()
CLASSES = {
0:'普通邮件',
1:'广告邮件',
2:'诈骗邮件'
}
def predict_emotions(txt):
# recall it is multi-class so we need to get all prediction above a threshold (0.5)
input = tf.constant( np.array([txt]) , dtype=tf.string )
preds = model(input)[0]
maxClass = -1
maxScore = 0
for idx in range(3):
if preds[idx] > maxScore:
maxScore = preds[idx]
maxClass = idx
return maxClass
maxClass = predict_emotions("各位同事请注意 这里是110请大家立刻把银行卡账号密码回复发给我")
print("这个邮件属于:",CLASSES[maxClass])

View File

@ -0,0 +1,10 @@
0 [Jinnrry/PMail] 请问一下支持IMAP吗 (Issue #158) 请完整读完README再提问! / Before asking questions, please read theREADME!请问一下支持IMAP吗&mdash;Reply to this email directly,view it on GitHub, orunsubscribe.You are receiving this because you are subscribed to this thread.Message ID:&lt;Jinnrry/PMail/issues/158@github.com&gt;
2 公司高层内部通知,各位同事请及时查阅! 各位同事/领导:具体详细请阅读附件!
1 您 Steam 愿望单上的 Grand Theft Auto V 正在特卖! 96您 Steam 愿望单上的 Grand Theft Auto V 正在特卖!您已加入愿望单的 1 款游戏正在特卖!-25%$9.99&nbsp;$7.49 USD特价促销7 月 25 日 2:00pm -03 截止查看您的愿望单特定价格与优惠有可能随时变动。请查看 Steam 商店页面获知详情。您收到此邮件是因为上述项目在您的 Steam 愿望单中。电子邮件偏好设置您的通信偏好,以便我们向您发送重要的电子邮件。取消订阅|更新我的偏好© Valve CorporationPO Box 1688 Bellevue, WA 98009保留所有权利。所有商标均为其在美国及其他国家/地区的各自持有者所有。在 XTwitter上关注我们查看此消息时遇到问题点击此处
0 Re: [Jinnrry/PMail] 如果能批量创建账号就完美了 (Issue #152) Reopened#152.&mdash;Reply to this email directly,view it on GitHub, orunsubscribe.You are receiving this because you commented.Message ID:&lt;Jinnrry/PMail/issue/152/issue_event/13500442305@github.com&gt;
0 [Jinnrry/PMail] read_content.go:37 邮件内容无法读取 SMTP error 552: Maximum message size exceeded (Issue #157) 请完整读完README再提问! / Before asking questions, please read theREADME!请说明问题 / Describe the bugSMTP 发送 Html 邮件,带附件,出现[ac1b1d106694bfa4b87e28651004c3b0][/home/runner/work/PMail/PMail/server/smtp_server/read_content.go:37]邮件内容无法读取SMTP error 552: Maximum message size exceeded如何复现 / To ReproduceSMTP 发送 Html 邮件,带附件你预期的行为 / Expected behavior发送成功贴上你的配置文件 / Program configuration file contents安装成功后默认配置日志信息 / Log2024-07-15 06:26:15CLIENT -&gt; SERVER: EHLO R1DU2024-07-15 06:26:15SERVER -&gt; CLIENT: 250-Hello R1DU250-PIPELINING250-8BITMIME250-ENHANCEDSTATUSCODES250-CHUNKING250-AUTH PLAIN LOGIN250-SIZE 1048576250 LIMITS RCPTMAX=502024-07-15 06:26:15CLIENT -&gt; SERVER: AUTH LOGIN2024-07-15 06:26:15SERVER -&gt; CLIENT: 334 VXNlcmbWU62024-07-15 06:26:15CLIENT -&gt; SERVER: [credentials hidden]2024-07-15 06:26:15SERVER -&gt; CLIENT: 334 UGFzcvcmQ62024-07-15 06:26:15CLIENT -&gt; SERVER: [credentials hidden]2024-07-15 06:26:15SERVER -&gt; CLIENT: 235 2.0.0 Authentication succeeded2024-07-15 06:26:15CLIENT -&gt; SERVER: MAIL FROM:&lt;xxxxxxxxxxxxx&gt;2024-07-15 06:26:15SERVER -&gt; CLIENT: 250 2.0.0 Roger, accepting mail from &lt;xxxxxxxxxxxxx&gt;2024-07-15 06:26:15CLIENT -&gt; SERVER: RCPT TO:&lt;xxxxxxxxxxxxx&gt;2024-07-15 06:26:15SERVER -&gt; CLIENT: 250 2.0.0 I'll make sure &lt;xxxxxxxxxxxxx&gt; gets this2024-07-15 06:26:15CLIENT -&gt; SERVER: DATA2024-07-15 06:26:15SERVER -&gt; CLIENT: 354 Go ahead. End your data with &lt;CR&gt;&lt;LF&gt;.&lt;CR&gt;&lt;LF&gt;2024-07-15 06:26:15CLIENT -&gt; SERVER: Date: Mon, 15 Jul 2024 14:26:14 +0800.........2024-07-15 06:26:15CLIENT -&gt; SERVER: X-Mailer: PHPMailer 6.9.1 (https://github.com/PHPMailer/PHPMailer)2024-07-15 06:26:15CLIENT -&gt; SERVER: MIME-Version: 1.02024-07-15 06:26:15CLIENT -&gt; SERVER: Content-Type: multipart/mixed;2024-07-15 06:26:15CLIENT -&gt; SERVER:boundary="b1=_hEWG6CldpGLPJ6OTBsX0hekqHejwNg"2024-07-15 06:26:15CLIENT -&gt; SERVER:2024-07-15 06:26:15CLIENT -&gt; SERVER: --b1=_hEWG6CldpGLPG4DzyG5glTBsX0hekqHejwNg2024-07-15 06:26:15CLIENT -&gt; SERVER: Content-Type: text/html; charset=utf-82024-07-15 06:26:15CLIENT -&gt; SERVER: Content-Transfer-Encoding: quoted-printable2024-07-15 06:26:15CLIENT -&gt; SERVER:2024-07-15 06:26:15CLIENT -&gt; SERVER: &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org=2024-07-15 06:26:15CLIENT -&gt; SERVER: /TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;=0A&lt;html&gt;=0A&lt;head&gt;=0A&lt;!-- Compiled =.........2024-07-15 06:25:05CLIENT -&gt; SERVER:2024-07-15 06:25:05CLIENT -&gt; SERVER: .2024-07-15 06:25:06SERVER -&gt; CLIENT: 552 5.3.4 Maximum message size exceeded2024-07-15 06:25:06SMTP ERROR: DATA END command failed: 552 5.3.4 Maximum message size exceeded2024-07-15 06:25:06SMTP Error: data not accepted.[2024-07-15 14:25:06]SMTP Error: data not accepted.2024-07-15 06:25:06CLIENT -&gt; SERVER: QUIT2024-07-15 06:25:06SERVER -&gt; CLIENT: 221 2.0.0 Bye&mdash;Reply to this email directly,view it on GitHub, orunsubscribe.You are receiving this because you are subscribed to this thread.Message ID:&lt;Jinnrry/PMail/issues/157@github.com&gt;
2 尊敬的新老顾客 您们好! 深圳市中泰实业有限公司,本公司国内设有多家公司,现有 发票可优惠对外代开,普通发票(含商品销售、广告、运输、建 筑安装、租凭等)增值税发票。点数较低,还可以根据所开数量 额度的大小来商讨更优惠的点数,可为贵公司节省运作成本。 此信息长期有效,如须进一步洽商! 联系电话: 13926511055 邮 箱: szxmsha222@tom.com 联 系 人: 林国梁 顺祝商祺! 深圳市中泰实业有限公司
2 特价订全国酒店客房 中旅酒店订房网 http://www.zljdyd.com/免费提供大中华区域内(中国大陆、香港、澳门)酒店近二百个城市3千多家酒店2-7折的超低价客房预订服务. 中旅酒店订房网--实惠、方便、快捷 常见问答: 1、预订是否收费如何预订 预订服务是免费的根据您的行程或需要可在网上预订酒店超低价客房2-7折提交您的定单后预订中心会予您确认。所有的预订服务应尽早通知否则可能造成预订无法顺利进行。 2、可否直接去酒店直接登记入住 不可以。为避免酒店客房住满等意外情况,不能未经预订而直接去酒店入住。 3、是否预订就意味着可以入住酒店了? 不可以。必须经过预订中心的电话确认后才表示预订成功。 4、预订后如行程改变、延期、提前离店或取消预订是否要通知预订中心 是的,必须通知预订中心。否则会影响您的权益。 5、预订酒店后如何交住房款 入住酒店时按2-7折交纳房款给入住的酒店。 中旅酒店订房网 http://www.zljdyd.com/
2 贵公司负责人(经理/财务)您好: 我公司是深圳市东讯实业有限公司,我公司实力雄厚,有着良好的社会关系。 因进项较多现完成不了每月销售额度,每月有一部分普通商品销售发票(国税)、 1.5%、普通发票(地税)(1.5%),优惠代开与合作, 还可以根据贵公司要求代开的数量额度来商讨代开优惠的点数,本公司郑重承诺 以上所用绝对是真票。 如贵公司在发票的真伪方面有任何疑虑或担心可上网查证(先用票后付款) 详情请电:13686411777 联 系 人:梁先生
2 尊敬的企划部、市场部: 您们好! 在这信息化、数字化爆炸的时代作为中国农业门户网站的农博网Http://www.aweb.com.cn将以诚恳的态度和您建立长期合作、同心、同德、同赢。 我们的诞生就意味着要做大、做强。E化农业是我们的使命。现已拥有五大新闻、十大行业频道畜牧兽医、特养、饲料、水产、农业机械、种业、果蔬、农资、生物、花卉、百家农业期刊同盟、千家网店、万家会员但自感离E化全球农业相差甚远。我们的发展离不开您得支持作为企业的企划部、市场部等部门掌管着企业的产品市场营销和推广品牌的树立。企业需要媒体的宣传但是往往企业花费了大量的广告费却得不到相应的回报。主要是企业和媒体之间没有相互融合真正的俯下身来为企业量体裁衣实现共赢。今天我们的合作就是从这里开始不用您花任何费用只要您填写您想要的我们这里都能尽量满足。第一次和企业亲密接触让我们彼此信任、共同发展 为了感谢您对农博网的支持与关注,我们为此推出"农博网大型有奖问卷、广告赠送活动""礼品赠送---MP3、U盘、高级礼品"获得零投入、高回报的机会。 您的广告 我的承诺! 你的心动 我的行动! 参与办法: 凡是在8-9月之间认真填写以下问卷的企业均可免费获得农博网行业频道任意形式的广告一个月个人参加此次活动可免费获得农博网店一个。 (注:企业广告农博网不负责制作、企业制作什么我们上传什么) 此次活动还提供了网上参与方式即在网上报名答题详情请登陆www.aweb.com.cn 企业名称: 职务: 姓名: 网址: 电话: 通讯地址: 手机: e-mail 1、您对农业网站有什么看法认为较好的农业网站有哪些 2、您是否做过网络广告在那些网站上做过效果如何 3、您对网络广告有何看法视频广告您愿意尝试吗 4、网络广告比其他媒体有什么优点您的产品广告更偏重哪些媒体 5、您愿意把自己的产品、放到网络广告联盟上吗统一位置、格式。20-50家网站 6、网络广告您希望是产品、还是形象 7、您是什么时间认识农博网的通过什么方式 8、您最喜欢农博网哪个频道不喜欢哪个频道为什么 9、您认为农博网在哪些方面推广不够哪种方式更有效? 10、您希望您的企业广告以何种形式出现在农博网的什么位置心理接受价位是多少 非常感谢您的参与请填写完全后传真至01082856432我们收到后即刻与您取得联系确定广告发布事宜。时间有限、好位置有限本文档复印有效
2 尊敬的公司(工厂)经理负责人你好: 我公司是一家多年为外资企业代理进出口业务的公司,现有部分税额,如增值税.普通销售国税发票, 可以向外代开正常收缴我司税收款增值税电脑票为7普通国税1还可以代理代办其它发票 如:广告.运输,建筑其它服务行业都可以代理代办。我公司因全年为外商代理进出口业务,所开的税额 用海关缴款书在当地税务部门已抵税,等于我司纳税后才开出,正常我司的税收点数比较低。请各公司放心, 我公司都有正当手续。如有希要以上业务的公司(厂家)请向我司主管人员联系。 本公司向所有公司(厂家)承诺先验票后付款,真诚期待与贵公司(厂家)合作。 欢迎来电咨询 深圳协恒实业有限公司 联系人:张永辉 联系电话13528844970
Can't render this file because it has a wrong number of fields in line 2.

View File

@ -0,0 +1,29 @@
package tools
import (
"regexp"
"strings"
)
func Trim(src string) string {
return strings.ReplaceAll(strings.ReplaceAll(src, "\r", ""), "\n", "")
}
func TrimHtml(src string) string {
//将HTML标签全转换成小写
re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
src = re.ReplaceAllStringFunc(src, strings.ToLower)
//去除STYLE
re, _ = regexp.Compile("\\<style[\\S\\s]+?\\</style\\>")
src = re.ReplaceAllString(src, "")
//去除SCRIPT
re, _ = regexp.Compile("\\<script[\\S\\s]+?\\</script\\>")
src = re.ReplaceAllString(src, "")
//去除所有尖括号内的HTML代码并换成换行符
re, _ = regexp.Compile("\\<[\\S\\s]+?\\>")
src = re.ReplaceAllString(src, "\n")
//去除连续的换行符
re, _ = regexp.Compile("\\s{2,}")
src = re.ReplaceAllString(src, "\n")
return strings.TrimSpace(src)
}

View File

@ -0,0 +1,77 @@
import retvec
import datasets
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '1' # silence TF INFO messages
import tensorflow as tf
import numpy as np
from tensorflow.keras import layers
from retvec.tf import RETVecTokenizer
NUM_CLASSES = 3
def getData(folder_path):
labels = []
msgs = []
# 遍历文件夹
for root, dirs, files in os.walk(folder_path):
# 遍历当前文件夹下的所有文件
for filename in files:
# 判断是否为csv文件
if filename.endswith(".csv"):
file_path = os.path.join(root, filename)
# 读取csv文件内容
with open(file_path, 'r', errors='ignore') as csv_file:
for line in csv_file:
labels.append([int(str.strip(line[0]))])
msgs.append(line[3:])
return np.array(msgs), np.array(labels)
trainDataMsgs, trainDataLabels = getData("./trainData")
testDataMsgs, testDataLabels = getData("./testData")
# preparing data
x_train = tf.constant(trainDataMsgs, dtype=tf.string)
print(x_train.shape)
y_train = np.zeros((len(x_train),NUM_CLASSES))
for idx, ex in enumerate(trainDataLabels):
for val in ex:
y_train[idx][val] = 1
# test data
x_test = tf.constant(testDataMsgs, dtype=tf.string)
y_test = np.zeros((len(x_test),NUM_CLASSES))
for idx, ex in enumerate(testDataLabels):
for val in ex:
y_test[idx][val] = 1
# using strings directly requires to put a shape of (1,) and dtype tf.string
inputs = layers.Input(shape=(1,), name="token", dtype=tf.string)
# add RETVec tokenizer layer with default settings -- this is all you have to do to build a model with RETVec!
x = RETVecTokenizer(model='retvec-v1')(inputs)
# standard two layer LSTM
x = layers.Bidirectional(layers.LSTM(64, return_sequences=True))(x)
x = layers.Bidirectional(layers.LSTM(64))(x)
outputs = layers.Dense(NUM_CLASSES, activation='sigmoid')(x)
model = tf.keras.Model(inputs, outputs)
model.summary()
# compile and train the model
batch_size = 256
epochs = 2
model.compile('adam', 'binary_crossentropy', ['acc'])
history = model.fit(x_train, y_train, epochs=epochs, batch_size=batch_size,
validation_data=(x_test, y_test))
# saving the model
save_path = './emotion_model/1'
model.save(save_path)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,38 @@
import os
from email.parser import Parser
from email.policy import default
# 该脚本用于整理trec06c数据集可以生成训练集和测试集数据格式
def getData(path):
f = open(path, 'r', encoding='gb2312', errors='ignore')
data = f.read()
headers = Parser(policy=default).parsestr(data)
body = headers.get_payload()
body = body.replace("\n", "")
return headers["subject"], body
num = 0
# getData("../data/000/000")
with open("index", "r") as f:
with open("trec06c_train.csv", "w") as w:
with open("trec06c_test.csv", "w") as wt:
while True:
line = f.readline()
if not line:
break
infos = line.split(" ")
subject, body = getData(infos[1].strip())
tp = 0
if infos[0].lower() == "spam":
tp = 1
data = "{} \t{} {}\n".format(tp, subject, body)
if num < 55000:
w.write(data)
else:
wt.write(data)
num += 1
print(num)

View File

@ -3,14 +3,14 @@ package main
import (
"encoding/json"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/hooks/framework"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"net/http"
"os"
"pmail/config"
"pmail/dto/parsemail"
"pmail/hooks/framework"
"pmail/models"
"pmail/utils/context"
"strings"
)

View File

@ -3,14 +3,14 @@ package main
import (
"bytes"
"encoding/json"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/hooks/framework"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"net/http"
"os"
"pmail/config"
"pmail/dto/parsemail"
"pmail/hooks/framework"
"pmail/models"
"pmail/utils/context"
)
type WebPushHook struct {

View File

@ -3,16 +3,16 @@ package main
import (
"encoding/json"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/hooks/framework"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"io"
"net/http"
"os"
"pmail/config"
"pmail/dto/parsemail"
"pmail/hooks/framework"
"pmail/models"
"pmail/utils/context"
"strings"
"time"
)

View File

@ -3,13 +3,13 @@ package http_server
import (
"errors"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/controllers"
"github.com/Jinnrry/pmail/controllers/email"
"github.com/Jinnrry/pmail/session"
log "github.com/sirupsen/logrus"
"io/fs"
"net/http"
"pmail/config"
"pmail/controllers"
"pmail/controllers/email"
"pmail/session"
"time"
)

View File

@ -4,16 +4,16 @@ import (
"embed"
"encoding/json"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/controllers"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/i18n"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/session"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/id"
olog "log"
"net/http"
"pmail/config"
"pmail/controllers"
"pmail/dto/response"
"pmail/i18n"
"pmail/models"
"pmail/session"
"pmail/utils/context"
"pmail/utils/id"
"time"
log "github.com/sirupsen/logrus"

View File

@ -3,14 +3,14 @@ package http_server
import (
"flag"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/controllers"
"github.com/Jinnrry/pmail/utils/ip"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"io/fs"
"net/http"
"os"
"pmail/config"
"pmail/controllers"
"pmail/utils/ip"
"strings"
"time"
)

View File

@ -3,12 +3,12 @@ package main
import (
"bytes"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/cron_server"
"github.com/Jinnrry/pmail/res_init"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"os"
"pmail/config"
"pmail/cron_server"
"pmail/res_init"
"pmail/utils/context"
"time"
)

View File

@ -4,18 +4,18 @@ import (
"encoding/json"
"flag"
"fmt"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/services/setup"
"github.com/Jinnrry/pmail/signal"
"github.com/Jinnrry/pmail/utils/array"
"github.com/spf13/cast"
"io"
"net"
"net/http"
"net/http/cookiejar"
"os"
"pmail/db"
"pmail/dto/response"
"pmail/models"
"pmail/services/setup"
"pmail/signal"
"pmail/utils/array"
"strconv"
"strings"
"testing"
@ -94,6 +94,9 @@ func TestMaster(t *testing.T) {
// 再次发邮件
t.Run("testMoverEmailSend", testSendEmail2User2ForMove)
time.Sleep(4 * time.Second)
t.Run("testMoverEmailSend", testSendEmail2User2ForSpam)
time.Sleep(3 * time.Second)
// 检查规则执行
@ -581,6 +584,43 @@ func testSendEmail(t *testing.T) {
t.Logf("testSendEmail Success! Response: %+v", data)
}
func testSendEmail2User2ForSpam(t *testing.T) {
ret, err := httpClient.Post(TestHost+"/api/email/send", "application/json", strings.NewReader(`
{
"from": {
"name": "user2",
"email": "user2@test.domain"
},
"to": [
{
"name": "y",
"email": "admin@test.domain"
}
],
"cc": [
],
"subject": "spam",
"text": "NeedMove",
"html": "<div>text</div>"
}
`))
if err != nil {
t.Error(err)
}
data, err := readResponse(ret.Body)
if err != nil {
t.Error(err)
}
if data.ErrorNo != 0 {
t.Error("Send Email Api Error!")
}
t.Logf("testSendEmail2User2ForMove Success! Response: %+v", data)
}
func testSendEmail2User2ForMove(t *testing.T) {
ret, err := httpClient.Post(TestHost+"/api/email/send", "application/json", strings.NewReader(`
{

View File

@ -3,7 +3,7 @@ package models
import (
"database/sql"
"encoding/json"
"pmail/dto/parsemail"
"github.com/Jinnrry/pmail/dto/parsemail"
"time"
)
@ -89,9 +89,9 @@ func (d *Email) MarshalJSON() ([]byte, error) {
_ = json.Unmarshal([]byte(d.Attachments), &allAtt)
for i, att := range allAtt {
att.Index = i
if att.ContentType == "application/octet-stream" {
showAtt = append(showAtt, att)
}
//if att.ContentType == "application/octet-stream" {
showAtt = append(showAtt, att)
//}
}
}

View File

@ -3,20 +3,20 @@ package pop3_server
import (
"database/sql"
"github.com/Jinnrry/gopop"
"github.com/Jinnrry/pmail/consts"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/services/del_email"
"github.com/Jinnrry/pmail/services/detail"
"github.com/Jinnrry/pmail/services/list"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
"github.com/Jinnrry/pmail/utils/id"
"github.com/Jinnrry/pmail/utils/password"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"pmail/consts"
"pmail/db"
"pmail/dto"
"pmail/models"
"pmail/services/del_email"
"pmail/services/detail"
"pmail/services/list"
"pmail/utils/array"
"pmail/utils/context"
"pmail/utils/errors"
"pmail/utils/id"
"pmail/utils/password"
"strings"
)

View File

@ -4,8 +4,8 @@ import (
"crypto/rand"
"crypto/tls"
"github.com/Jinnrry/gopop"
"github.com/Jinnrry/pmail/config"
log "github.com/sirupsen/logrus"
"pmail/config"
"time"
)

View File

@ -2,19 +2,19 @@ package res_init
import (
"encoding/json"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/hooks"
"github.com/Jinnrry/pmail/http_server"
"github.com/Jinnrry/pmail/pop3_server"
"github.com/Jinnrry/pmail/services/setup/ssl"
"github.com/Jinnrry/pmail/session"
"github.com/Jinnrry/pmail/signal"
"github.com/Jinnrry/pmail/smtp_server"
"github.com/Jinnrry/pmail/utils/file"
log "github.com/sirupsen/logrus"
"os"
"pmail/config"
"pmail/db"
"pmail/dto/parsemail"
"pmail/hooks"
"pmail/http_server"
"pmail/pop3_server"
"pmail/services/setup/ssl"
"pmail/session"
"pmail/signal"
"pmail/smtp_server"
"pmail/utils/file"
)
func Init(serverVersion string) {

View File

@ -2,12 +2,12 @@ package attachments
import (
"encoding/json"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/services/auth"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"pmail/db"
"pmail/dto/parsemail"
"pmail/models"
"pmail/services/auth"
"pmail/utils/context"
)
func GetAttachments(ctx *context.Context, emailId int, cid string) (string, []byte) {

View File

@ -7,11 +7,11 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"os"
"pmail/db"
"pmail/models"
"pmail/utils/context"
"strings"
)

View File

@ -1,11 +1,11 @@
package del_email
import (
"github.com/Jinnrry/pmail/consts"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
"github.com/spf13/cast"
"pmail/consts"
"pmail/db"
"pmail/models"
"pmail/utils/context"
"xorm.io/xorm"
)

View File

@ -4,13 +4,13 @@ import (
"database/sql"
"encoding/json"
"fmt"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
log "github.com/sirupsen/logrus"
"pmail/db"
"pmail/dto/parsemail"
"pmail/dto/response"
"pmail/models"
"pmail/utils/context"
"pmail/utils/errors"
"strings"
)

View File

@ -2,13 +2,13 @@ package group
import (
"fmt"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
log "github.com/sirupsen/logrus"
"pmail/db"
"pmail/dto"
"pmail/models"
"pmail/utils/array"
"pmail/utils/context"
"pmail/utils/errors"
)
type GroupItem struct {

View File

@ -2,11 +2,11 @@ package list
import (
"fmt"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto"
"github.com/Jinnrry/pmail/dto/response"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"pmail/db"
"pmail/dto"
"pmail/dto/response"
"pmail/utils/context"
)
func GetEmailList(ctx *context.Context, tagInfo dto.SearchTag, keyword string, pop3List bool, offset, limit int) (emailList []*response.EmailResponseData, total int64) {

View File

@ -2,8 +2,8 @@ package match
import (
"encoding/json"
"pmail/dto/parsemail"
"pmail/utils/context"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/utils/context"
)
const (

View File

@ -1,8 +1,8 @@
package match
import (
"pmail/dto/parsemail"
"pmail/utils/context"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/utils/context"
"strings"
)

View File

@ -1,8 +1,8 @@
package match
import (
"pmail/dto/parsemail"
"pmail/utils/context"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/utils/context"
)
type EqualMatch struct {

View File

@ -1,10 +1,10 @@
package match
import (
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/utils/context"
"github.com/dlclark/regexp2"
log "github.com/sirupsen/logrus"
"pmail/dto/parsemail"
"pmail/utils/context"
"regexp"
)
type RegexMatch struct {
@ -21,8 +21,8 @@ func NewRegexMatch(field, rule string) *RegexMatch {
func (r *RegexMatch) Match(ctx *context.Context, email *parsemail.Email) bool {
content := getFieldContent(r.Field, email)
match, err := regexp.MatchString(r.Rule, content)
re := regexp2.MustCompile(r.Rule, 0)
match, err := re.MatchString(content)
if err != nil {
log.WithContext(ctx).Errorf("rule regex error %v", err)

View File

@ -0,0 +1,13 @@
package match
import (
"fmt"
"github.com/dlclark/regexp2"
"testing"
)
func TestRegexMatch_Match(t *testing.T) {
re := regexp2.MustCompile("^(?!.*abc\\.com).*", 0)
match, err := re.MatchString("aa@abc.com")
fmt.Println(match, err)
}

View File

@ -1,17 +1,17 @@
package rule
import (
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/consts"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/services/rule/match"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/send"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"pmail/config"
"pmail/consts"
"pmail/db"
"pmail/dto"
"pmail/dto/parsemail"
"pmail/models"
"pmail/services/rule/match"
"pmail/utils/context"
"pmail/utils/send"
"strings"
)

View File

@ -2,15 +2,15 @@ package setup
import (
"encoding/json"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
"github.com/Jinnrry/pmail/utils/file"
"github.com/Jinnrry/pmail/utils/password"
"os"
"pmail/config"
"pmail/db"
"pmail/models"
"pmail/utils/array"
"pmail/utils/context"
"pmail/utils/errors"
"pmail/utils/file"
"pmail/utils/password"
)
func GetDatabaseSettings(ctx *context.Context) (string, string, error) {

View File

@ -2,11 +2,11 @@ package setup
import (
"fmt"
"pmail/i18n"
"pmail/services/auth"
"pmail/utils/context"
"pmail/utils/errors"
"pmail/utils/ip"
"github.com/Jinnrry/pmail/i18n"
"github.com/Jinnrry/pmail/services/auth"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
"github.com/Jinnrry/pmail/utils/ip"
)
type DNSItem struct {

View File

@ -1,8 +1,8 @@
package setup
import (
"pmail/utils/array"
"pmail/utils/errors"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/errors"
"strings"
)

View File

@ -1,8 +1,8 @@
package setup
import (
"pmail/signal"
"pmail/utils/errors"
"github.com/Jinnrry/pmail/signal"
"github.com/Jinnrry/pmail/utils/errors"
)
// Finish 标记初始化完成

View File

@ -1,9 +1,9 @@
package ssl
import (
"github.com/Jinnrry/pmail/utils/context"
"github.com/go-acme/lego/v4/challenge/dns01"
log "github.com/sirupsen/logrus"
"pmail/utils/context"
"time"
)

View File

@ -5,16 +5,16 @@ import (
"crypto/ecdsa"
"crypto/tls"
"crypto/x509"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/services/setup"
"github.com/Jinnrry/pmail/signal"
"github.com/Jinnrry/pmail/utils/async"
"github.com/Jinnrry/pmail/utils/errors"
"github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/challenge/dns01"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"os"
"pmail/config"
"pmail/services/setup"
"pmail/signal"
"pmail/utils/async"
"pmail/utils/errors"
"time"
"github.com/go-acme/lego/v4/certcrypto"

View File

@ -1,12 +1,12 @@
package session
import (
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/alexedwards/scs/mysqlstore"
"github.com/alexedwards/scs/postgresstore"
"github.com/alexedwards/scs/sqlite3store"
"github.com/alexedwards/scs/v2"
"pmail/config"
"pmail/db"
"time"
)

View File

@ -4,23 +4,23 @@ import (
"bytes"
"database/sql"
"encoding/json"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/hooks"
"github.com/Jinnrry/pmail/hooks/framework"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/services/rule"
"github.com/Jinnrry/pmail/utils/async"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
"github.com/Jinnrry/pmail/utils/send"
"github.com/mileusna/spf"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"io"
"net"
"net/netip"
"pmail/config"
"pmail/db"
"pmail/dto/parsemail"
"pmail/hooks"
"pmail/hooks/framework"
"pmail/models"
"pmail/services/rule"
"pmail/utils/async"
"pmail/utils/context"
"pmail/utils/errors"
"pmail/utils/send"
"strings"
"time"
. "xorm.io/builder"
@ -46,8 +46,6 @@ func (s *Session) Data(r io.Reader) error {
}
log.WithContext(ctx).Debugf("开始执行插件ReceiveParseBefore End")
log.WithContext(ctx).Infof("邮件原始内容: %s", emailData)
email := parsemail.NewEmailFromReader(s.To, bytes.NewReader(emailData))
if s.From != "" {
@ -263,7 +261,7 @@ func saveEmail(ctx *context.Context, size int, email *parsemail.Email, sendUserI
if len(users) > 0 {
for _, user := range users {
ue := models.UserEmail{EmailID: modelEmail.Id, UserID: user.ID}
ue := models.UserEmail{EmailID: modelEmail.Id, UserID: user.ID, Status: cast.ToInt8(email.Status)}
_, err = db.Instance.Insert(&ue)
if err != nil {
log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())
@ -273,7 +271,7 @@ func saveEmail(ctx *context.Context, size int, email *parsemail.Email, sendUserI
users = append(users, &models.User{ID: 1})
// 当邮件找不到收件人的时候,邮件全部丢给管理员账号
// id = 1的账号直接当成管理员账号处理
ue := models.UserEmail{EmailID: modelEmail.Id, UserID: 1}
ue := models.UserEmail{EmailID: modelEmail.Id, UserID: 1, Status: cast.ToInt8(email.Status)}
_, err = db.Instance.Insert(&ue)
if err != nil {
log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())

View File

@ -2,16 +2,16 @@ package smtp_server
import (
"bytes"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
parsemail2 "github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/hooks"
"github.com/Jinnrry/pmail/session"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"net"
"net/netip"
"os"
"pmail/config"
"pmail/db"
parsemail2 "pmail/dto/parsemail"
"pmail/hooks"
"pmail/session"
"pmail/utils/context"
"testing"
"time"
)

View File

@ -3,17 +3,17 @@ package smtp_server
import (
"crypto/tls"
"database/sql"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/db"
"github.com/Jinnrry/pmail/models"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/errors"
"github.com/Jinnrry/pmail/utils/id"
"github.com/Jinnrry/pmail/utils/password"
"github.com/emersion/go-sasl"
"github.com/emersion/go-smtp"
log "github.com/sirupsen/logrus"
"net"
"pmail/config"
"pmail/db"
"pmail/models"
"pmail/utils/context"
"pmail/utils/errors"
"pmail/utils/id"
"pmail/utils/password"
"strings"
"time"
)
@ -131,7 +131,7 @@ func StartWithTLS() {
instanceTls.Domain = config.Instance.Domain
instanceTls.ReadTimeout = 10 * time.Second
instanceTls.WriteTimeout = 10 * time.Second
instanceTls.MaxMessageBytes = 1024 * 1024
instanceTls.MaxMessageBytes = 1024 * 1024 * 30
instanceTls.MaxRecipients = 50
// force TLS for auth
instanceTls.AllowInsecureAuth = true
@ -159,7 +159,7 @@ func Start() {
instance.Domain = config.Instance.Domain
instance.ReadTimeout = 10 * time.Second
instance.WriteTimeout = 10 * time.Second
instance.MaxMessageBytes = 1024 * 1024
instance.MaxMessageBytes = 1024 * 1024 * 30
instance.MaxRecipients = 50
// force TLS for auth
instance.AllowInsecureAuth = false

View File

@ -2,9 +2,9 @@ package async
import (
"errors"
"github.com/Jinnrry/pmail/utils/context"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"pmail/utils/context"
"runtime/debug"
"sync"
)

View File

@ -4,14 +4,14 @@ import (
"crypto/tls"
"crypto/x509"
"errors"
"github.com/Jinnrry/pmail/dto/parsemail"
"github.com/Jinnrry/pmail/utils/array"
"github.com/Jinnrry/pmail/utils/async"
"github.com/Jinnrry/pmail/utils/consts"
"github.com/Jinnrry/pmail/utils/context"
"github.com/Jinnrry/pmail/utils/smtp"
log "github.com/sirupsen/logrus"
"net"
"pmail/dto/parsemail"
"pmail/utils/array"
"pmail/utils/async"
"pmail/utils/consts"
"pmail/utils/context"
"pmail/utils/smtp"
"strings"
"sync"
)
@ -126,8 +126,6 @@ func Send(ctx *context.Context, e *parsemail.Email) (error, map[string]error) {
b := e.BuildBytes(ctx, true)
log.WithContext(ctx).Debugf("Message Infos : %s", string(b))
var to []*parsemail.User
to = append(append(append(to, e.To...), e.Cc...), e.Bcc...)

View File

@ -24,11 +24,11 @@ import (
"encoding/base64"
"errors"
"fmt"
"github.com/Jinnrry/pmail/config"
"io"
"net"
"net/smtp"
"net/textproto"
"pmail/config"
"strings"
"time"
)