pop3收件箱出现已删除邮件bug
从sqlx切换到xorm
第三方客户端发信出现在草稿箱bug
This commit is contained in:
jinnrry 2024-04-13 09:26:34 +08:00
parent 096b4b8fed
commit cc4aa851bc
43 changed files with 256 additions and 396 deletions

View File

@ -48,7 +48,7 @@ First go to [spamhaus](https://check.spamhaus.org/) and check your domain name a
## 2、Run
`./pmail`
`./pmail` (Set the http port for the initialization interface with `-p` )
Or

View File

@ -53,7 +53,7 @@ PMail是一个追求极简部署流程、极致资源占用的个人域名邮箱
## 2、运行
`./pmail`
`./pmail` (通过`-p`参数指定初始化界面的http端口)
或者

View File

@ -1,11 +1,8 @@
package config
import (
"embed"
"encoding/json"
"io/fs"
"os"
"strings"
)
var IsInit bool
@ -38,9 +35,6 @@ type Config struct {
TablesInitData map[string]string `json:"-"`
}
//go:embed tables/*
var tableConfig embed.FS
const DBTypeMySQL = "mysql"
const DBTypeSQLite = "sqlite"
const SSLTypeAuto = "0" //自动生成证书
@ -76,38 +70,6 @@ func Init() {
Instance.Domains = []string{Instance.Domain}
}
// 读取表设置
Instance.Tables = map[string]string{}
Instance.TablesInitData = map[string]string{}
root := "tables/mysql"
if Instance.DbType == DBTypeSQLite {
root = "tables/sqlite"
}
err = fs.WalkDir(tableConfig, root, func(path string, info fs.DirEntry, err error) error {
if !info.IsDir() && strings.HasSuffix(info.Name(), ".sql") {
tableName := strings.ReplaceAll(info.Name(), ".sql", "")
i, e := tableConfig.ReadFile(path)
if e != nil {
panic(e)
}
if len(i) == 0 || strings.TrimSpace(string(i)) == "" {
return nil
}
if strings.Contains(path, "data") {
Instance.TablesInitData[tableName] = string(i)
} else {
Instance.Tables[tableName] = string(i)
}
}
return nil
})
if err != nil {
panic(err)
}
if Instance.Domain != "" && Instance.IsInit {
IsInit = true
}

View File

@ -1,27 +0,0 @@
CREATE table email
(
id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id',
type tinyint(4) NOT NULL DEFAULT 0 COMMENT '邮件类型0:收到的邮件1:发送的邮件',
group_id int unsigned NOT NULL DEFAULT 0 COMMENT '分组id',
subject varchar(1000) NOT NULL DEFAULT '' COMMENT '邮件标题',
reply_to json COMMENT '回复人',
from_name varchar(50) NOT NULL DEFAULT '' COMMENT '发件人名称',
from_address varchar(150) NOT NULL DEFAULT '' COMMENT '发件人邮件地址',
`to` json COMMENT '收件人信息',
bcc json COMMENT '抄送',
cc json COMMENT '抄送',
`text` text COMMENT '邮件文本内容',
html mediumtext COMMENT 'html格式内容',
sender json COMMENT '发件人',
attachments json COMMENT '附件内容',
spf_check tinyint(1) DEFAULT 0 COMMENT '0未校验1校验通过2校验未通过',
dkim_check tinyint(1) DEFAULT 0 COMMENT '0未校验1校验通过2校验未通过',
status tinyint(4) NOT NULL DEFAULT 0 COMMENT '0未发送1已发送2发送失败3删除',
send_user_id int unsigned NOT NULL DEFAULT 0 COMMENT '发件人用户id',
is_read tinyint(1) NOT NULL DEFAULT 0 COMMENT '未读0已读1',
error text COMMENT '错误信息记录',
cron_send_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '定时发送邮件的发送时间',
send_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '发件日期',
create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
)COMMENT='邮件内容表'

View File

@ -1,7 +0,0 @@
CREATE TABLE `group`
(
id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id',
name varchar(10) NOT NULL DEFAULT '' COMMENT '分组名称',
user_id INT unsigned NOT NULL DEFAULT 0 COMMENT '用户id',
parent_id INT unsigned COMMENT '父级组ID'
)COMMENT='分组信息表'

View File

@ -1,10 +0,0 @@
CREATE TABLE `rule`
(
id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id',
user_id int NOT NULL DEFAULT 0 COMMENT '用户id',
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '规则名称',
`value` json NOT NULL COMMENT '规则内容',
action int not null default 0 comment '执行动作,1已读2转发3删除',
params varchar(255) not null default '' comment '执行参数',
sort int not null default 0 COMMENT '排序,越大约优先'
) COMMENT '收信规则表'

View File

@ -1,7 +0,0 @@
CREATE TABLE sessions
(
token CHAR(43) PRIMARY KEY,
data BLOB NOT NULL,
expiry TIMESTAMP(6) NOT NULL,
KEY `sessions_expiry_idx` (`expiry`)
)COMMENT='系统session数据表';

View File

@ -1,8 +0,0 @@
CREATE TABLE user
(
id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id',
account varchar(20) COMMENT '账号登陆名',
name varchar(10) COMMENT '用户名',
password char(32) COMMENT '登陆密码两次md5加盐md5(md5(password+"pmail") +"pmail2023")',
UNIQUE INDEX udx_account ( account )
)COMMENT='登陆信息表'

View File

@ -1,8 +0,0 @@
CREATE TABLE user_auth
(
id INT unsigned AUTO_INCREMENT PRIMARY KEY COMMENT '自增id',
user_id int COMMENT '用户id',
email_account varchar(30) COMMENT '收件人前缀',
UNIQUE INDEX udx_uid_ename ( user_id, email_account),
UNIQUE INDEX udx_ename_uid ( email_account,user_id )
)COMMENT='登陆信息表'

View File

@ -1,27 +0,0 @@
CREATE table email
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
type tinyint(4) NOT NULL DEFAULT 0,
group_id INTEGER NOT NULL DEFAULT 0,
subject varchar(1000) NOT NULL DEFAULT '',
reply_to json,
from_name varchar(50) NOT NULL DEFAULT '',
from_address varchar(150) NOT NULL DEFAULT '',
`to` json,
bcc json,
cc json,
`text` text,
html text,
sender json,
attachments json ,
spf_check tinyint(1) DEFAULT 0 ,
dkim_check tinyint(1) DEFAULT 0 ,
status tinyint(4) NOT NULL DEFAULT 0 ,
send_user_id int unsigned NOT NULL DEFAULT 0 ,
is_read tinyint(1) NOT NULL DEFAULT 0 ,
error text ,
cron_send_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ,
send_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ,
create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ,
update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
)

View File

@ -1,7 +0,0 @@
CREATE TABLE `group`
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name varchar(10) NOT NULL DEFAULT '',
parent_id INTEGER NOT NULL DEFAULT 0,
user_id INTEGER NOT NULL DEFAULT 0
)

View File

@ -1,10 +0,0 @@
create table rule
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id int,
name varchar(255) default '' not null,
value json not null,
action int default 0 not null,
params varchar(255) default '' not null,
sort int default 0 not null
)

View File

@ -1,8 +0,0 @@
CREATE TABLE sessions
(
token TEXT PRIMARY KEY,
data BLOB NOT NULL,
expiry REAL NOT NULL
);
CREATE INDEX sessions_expiry_idx ON sessions (expiry);

View File

@ -1,8 +0,0 @@
CREATE TABLE user
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
account varchar(20),
name varchar(10),
password char(32)
);
CREATE UNIQUE INDEX udx_account on user (account);

View File

@ -1,9 +0,0 @@
CREATE TABLE user_auth
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id int ,
email_account varchar(30)
);
CREATE UNIQUE INDEX udx_uid_ename on user_auth ( user_id, email_account);
CREATE UNIQUE INDEX udx_ename_uid on user_auth ( email_account,user_id );

View File

@ -37,6 +37,10 @@ func GetUserGroup(ctx *context.Context, w http.ResponseWriter, req *http.Request
Label: i18n.GetText(ctx.Lang, "sketch"),
Tag: dto.SearchTag{Type: 1, Status: 0}.ToString(),
},
{
Label: i18n.GetText(ctx.Lang, "deleted"),
Tag: dto.SearchTag{Type: -1, Status: 3}.ToString(),
},
},
},
}

View File

@ -35,9 +35,8 @@ func Login(ctx *context.Context, w http.ResponseWriter, req *http.Request) {
var user models.User
encodePwd := password.Encode(reqData.Password)
err = db.Instance.Get(&user, db.WithContext(ctx, "select * from user where account =? and password =?"),
reqData.Account, encodePwd)
_, err = db.Instance.Where("account =? and password =?", reqData.Account, encodePwd).Get(&user)
if err != nil && err != sql.ErrNoRows {
log.Errorf("%+v", err)
}

View File

@ -3,16 +3,14 @@ package db
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
log "github.com/sirupsen/logrus"
_ "modernc.org/sqlite"
"pmail/config"
"pmail/utils/context"
"pmail/utils/errors"
"strings"
"xorm.io/xorm"
)
var Instance *sqlx.DB
var Instance *xorm.Engine
func Init() error {
dsn := config.Instance.DbDSN
@ -20,9 +18,9 @@ func Init() error {
switch config.Instance.DbType {
case "mysql":
Instance, err = sqlx.Open("mysql", dsn)
Instance, err = xorm.NewEngine("mysql", dsn)
case "sqlite":
Instance, err = sqlx.Open("sqlite", dsn)
Instance, err = xorm.NewEngine("sqlite", dsn)
default:
return errors.New("Database Type Error!")
}
@ -31,10 +29,7 @@ func Init() error {
}
Instance.SetMaxOpenConns(100)
Instance.SetMaxIdleConns(10)
//showMySQLCharacterSet()
checkTable()
// 处理版本升级带来的数据表变更
databaseUpdate()
return nil
}
@ -45,74 +40,3 @@ func WithContext(ctx *context.Context, sql string) string {
}
return sql
}
type tables struct {
TablesInPmail string `db:"Tables_in_pmail"`
}
func checkTable() {
var res []*tables
var err error
if config.Instance.DbType == "sqlite" {
err = Instance.Select(&res, "select name as `Tables_in_pmail` from sqlite_master where type='table'")
} else {
err = Instance.Select(&res, "show tables")
}
if err != nil {
panic(err)
}
existTable := map[string]struct{}{}
for _, tableName := range res {
existTable[tableName.TablesInPmail] = struct{}{}
}
for tableName, createSQL := range config.Instance.Tables {
if createSQL == "" {
continue
}
if _, ok := existTable[tableName]; !ok {
_, err = Instance.Exec(createSQL)
log.Infof("Create Table: %s", createSQL)
if err != nil {
panic(err)
}
if initData, ok := config.Instance.TablesInitData[tableName]; ok {
if initData != "" {
_, err = Instance.Exec(initData)
log.Infof("Init Table: %s", initData)
if err != nil {
panic(err)
}
}
}
}
}
}
type tableSQL struct {
Table string `db:"Table"`
CreateTable string `db:"Create Table"`
}
func databaseUpdate() {
// 检查email表是否有group id
var err error
var res []tableSQL
if config.Instance.DbType == "sqlite" {
err = Instance.Select(&res, "select sql as `Create Table` from sqlite_master where type='table' and tbl_name = 'email'")
} else {
err = Instance.Select(&res, "show create table `email`")
}
if err != nil {
panic(err)
}
if len(res) > 0 && !strings.Contains(res[0].CreateTable, "group_id") {
Instance.Exec("alter table email add group_id integer default 0 not null;")
}
}

View File

@ -13,13 +13,13 @@ require (
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.6.0
golang.org/x/crypto v0.22.0
golang.org/x/text v0.14.0
modernc.org/sqlite v1.29.6
xorm.io/xorm v1.3.9
)
require (
@ -27,12 +27,18 @@ require (
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.58 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/syndtr/goleveldb v1.0.0 // 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
@ -44,4 +50,5 @@ require (
modernc.org/memory v1.8.0 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
xorm.io/builder v0.3.13 // indirect
)

View File

@ -1,5 +1,7 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
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/alexedwards/scs/mysqlstore v0.0.0-20240316134038-7e11d57e8885 h1:C7QAamNjR5yz6di4KJWAKcnxueKBgq4L/JGXhlnu35w=
@ -26,30 +28,37 @@ github.com/emersion/go-smtp v0.21.0 h1:ZDZmX9aFUuPlD1lpoT0nC/nozZuIkSCyQIyxdijjC
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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
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.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
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.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/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
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/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=
@ -60,8 +69,18 @@ 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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
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-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
@ -73,9 +92,12 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
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.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/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
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=
@ -88,6 +110,7 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.8.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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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=
@ -97,12 +120,14 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
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-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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=
@ -139,6 +164,13 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
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=
@ -168,3 +200,7 @@ 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=
xorm.io/builder v0.3.13 h1:a3jmiVVL19psGeXx8GIurTp7p0IIgqeDmwhcR6BAOAo=
xorm.io/builder v0.3.13/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/xorm v1.3.9 h1:TUovzS0ko+IQ1XnNLfs5dqK1cJl1H5uHpWbWqAQ04nU=
xorm.io/xorm v1.3.9/go.mod h1:LsCCffeeYp63ssk0pKumP6l96WZcHix7ChpurcLNuMw=

View File

@ -14,6 +14,7 @@ var (
"login_exp": "登录已失效",
"ip_taps": "这是你服务器IP确保这个IP正确",
"invalid_email_address": "无效的邮箱地址!",
"deleted": "垃圾箱",
}
en = map[string]string{
"all_email": "All Email",
@ -28,6 +29,7 @@ var (
"login_exp": "Login has expired.",
"ip_taps": "This is your server's IP, make sure it is correct.",
"invalid_email_address": "Invalid e-mail address!",
"deleted": "Deleted",
}
)

View File

@ -1,8 +1,12 @@
package models
type User struct {
ID int `db:"id"`
Account string `db:"account"`
Name string `db:"name"`
Password string `db:"password"`
ID int `xorm:"id unsigned int not null pk autoincr"`
Account string `xorm:"varchar(20) notnull unique comment('账号登陆名')"`
Name string `xorm:"varchar(10) notnull comment('用户名')"`
Password string `xorm:"char(32) notnull comment('登陆密码两次md5加盐md5(md5(password+pmail) +pmail2023)')"`
}
func (p User) TableName() string {
return "user"
}

View File

@ -1,7 +1,11 @@
package models
type UserAuth struct {
ID int `db:"id"`
UserID int `db:"user_id"`
EmailAccount string `db:"email_account"`
ID int `xorm:"id int unsigned not null pk autoincr"`
UserID int `xorm:"user_id int not null unique('uid_account') index comment('用户id')"`
EmailAccount string `xorm:"email_account not null unique('uid_account') index comment('收信人前缀')"`
}
func (p UserAuth) TableName() string {
return "user_auth"
}

View File

@ -8,30 +8,34 @@ import (
)
type Email struct {
Id int `db:"id" json:"id"`
Type int8 `db:"type" json:"type"`
GroupId int `db:"group_id" json:"group_id"`
Subject string `db:"subject" json:"subject"`
ReplyTo string `db:"reply_to" json:"reply_to"`
FromName string `db:"from_name" json:"from_name"`
FromAddress string `db:"from_address" json:"from_address"`
To string `db:"to" json:"to"`
Bcc string `db:"bcc" json:"bcc"`
Cc string `db:"cc" json:"cc"`
Text sql.NullString `db:"text" json:"text"`
Html sql.NullString `db:"html" json:"html"`
Sender string `db:"sender" json:"sender"`
Attachments string `db:"attachments" json:"attachments"`
SPFCheck int8 `db:"spf_check" json:"spf_check"`
DKIMCheck int8 `db:"dkim_check" json:"dkim_check"`
Status int8 `db:"status" json:"status"` // 0未发送1已发送2发送失败3删除
CronSendTime time.Time `db:"cron_send_time" json:"cron_send_time"`
UpdateTime time.Time `db:"update_time" json:"update_time"`
SendUserID int `db:"send_user_id" json:"send_user_id"`
IsRead int8 `db:"is_read" json:"is_read"`
Error sql.NullString `db:"error" json:"error"`
SendDate time.Time `db:"send_date" json:"send_date"`
CreateTime time.Time `db:"create_time" json:"create_time"`
Id int `xorm:"id pk unsigned int autoincr notnull" json:"id"`
Type int8 `xorm:"type tinyint(4) notnull default(0) comment('邮件类型0:收到的邮件1:发送的邮件')" json:"type"`
GroupId int `xorm:"group_id int notnull default(0) comment('分组id')'" json:"group_id"`
Subject string `xorm:"subject varchar(1000) notnull default('') comment('邮件标题')" json:"subject"`
ReplyTo string `xorm:"reply_to text comment('回复人')" json:"reply_to"`
FromName string `xorm:"from_name varchar(50) notnull default('') comment('发件人名称')" json:"from_name"`
FromAddress string `xorm:"from_address varchar(100) notnull default('') comment('发件人邮件地址')" json:"from_address"`
To string `xorm:"to text comment('收件人地址')" json:"to"`
Bcc string `xorm:"bcc text comment('密送')" json:"bcc"`
Cc string `xorm:"cc text comment('抄送')" json:"cc"`
Text sql.NullString `xorm:"text text comment('文本内容')" json:"text"`
Html sql.NullString `xorm:"html mediumtext comment('html内容')" json:"html"`
Sender string `xorm:"sender text comment('发送人')" json:"sender"`
Attachments string `xorm:"attachments longtext comment('附件')" json:"attachments"`
SPFCheck int8 `xorm:"spf_check tinyint(1) comment('spf校验是否通过')" json:"spf_check"`
DKIMCheck int8 `xorm:"dkim_check tinyint(1) comment('dkim校验是否通过')" json:"dkim_check"`
Status int8 `xorm:"status tinyint(4) notnull default(0) comment('0未发送1已发送2发送失败3删除')" json:"status"` // 0未发送1已发送2发送失败3删除
CronSendTime time.Time `xorm:"cron_send_time comment('定时发送时间')" json:"cron_send_time"`
UpdateTime time.Time `xorm:"update_time updated comment('更新时间')" json:"update_time"`
SendUserID int `xorm:"send_user_id unsigned int notnull default(0) comment('发件人用户id')" json:"send_user_id"`
IsRead int8 `xorm:"is_read tinyint(1) comment('是否已读')" json:"is_read"`
Error sql.NullString `xorm:"error text comment('投递错误信息')" json:"error"`
SendDate time.Time `xorm:"send_date comment('投递时间')" json:"send_date"`
CreateTime time.Time `xorm:"create_time created" json:"create_time"`
}
func (p Email) TableName() string {
return "email"
}
type attachments struct {

View File

@ -1,8 +1,12 @@
package models
type Group struct {
ID int `db:"id" json:"id"`
Name string `db:"name" json:"name"`
ParentId int `db:"parent_id" json:"parent_id"`
UserId int `db:"user_id" json:"-"`
ID int `xorm:"id int unsigned not null pk autoincr" json:"id"`
Name string `xorm:"varchar(10) notnull default('') comment('分组名称')" json:"name"`
ParentId int `xorm:"parent_id int unsigned notnull default(0) comment('父分组名称')" json:"parent_id"`
UserId int `xorm:"user_id int unsigned notnull default(0) comment('用户id')" json:"-"`
}
func (p *Group) TableName() string {
return "group"
}

View File

@ -7,13 +7,17 @@ import (
)
type Rule struct {
Id int `db:"id" json:"id"`
UserId string `db:"user_id" json:"user_id"`
Name string `db:"name" json:"name"`
Value string `db:"value" json:"value"`
Action int `db:"action" json:"action"`
Params string `db:"params" json:"params"`
Sort int `db:"sort" json:"sort"`
Id int `xorm:"id int unsigned not null pk autoincr" json:"id"`
UserId int `xorm:"user_id notnull default(0) comment('用户id')" json:"user_id"`
Name string `xorm:"name notnull default('') comment('规则名称')" json:"name"`
Value string `xorm:"value text comment('规则内容')" json:"value"`
Action int `xorm:"action notnull default(0) comment('执行动作,1已读2转发3删除')" json:"action"`
Params string `xorm:"params notnull default('') comment('执行参数')" json:"params"`
Sort int `xorm:"sort notnull default(0) comment('排序,越大约优先')" json:"sort"`
}
func (p *Rule) TableName() string {
return "rule"
}
func (p *Rule) Save(ctx *context.Context) error {

View File

@ -100,7 +100,7 @@ func (a action) Pass(session *gopop.Session, pwd string) error {
encodePwd := password.Encode(pwd)
err := db.Instance.Get(&user, db.WithContext(session.Ctx.(*context.Context), "select * from user where account =? and password =?"), session.User, encodePwd)
_, err := db.Instance.Where("account =? and password =?", session.User, encodePwd).Get(&user)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
log.WithContext(session.Ctx.(*context.Context)).Errorf("%+v", err)
}
@ -136,7 +136,7 @@ func (a action) Apop(session *gopop.Session, username, digest string) error {
var user models.User
err := db.Instance.Get(&user, db.WithContext(session.Ctx.(*context.Context), "select * from user where account =? "), username)
_, err := db.Instance.Where("account =? ", username).Get(&user)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
log.WithContext(session.Ctx.(*context.Context)).Errorf("%+v", err)
}
@ -166,7 +166,7 @@ func (a action) Stat(session *gopop.Session) (msgNum, msgSize int64, err error)
log.WithContext(session.Ctx).Debugf("POP3 CMD: STAT")
var si statInfo
err = db.Instance.Get(&si, db.WithContext(session.Ctx.(*context.Context), "select count(1) as `num`, sum(length(text)+length(html)) as `size` from email where type = 0"))
_, err = db.Instance.Select("count(1) as `num`, sum(length(text)+length(html)) as `size`").Table("email").Where("type=0 and status=0").Get(&si)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
log.WithContext(session.Ctx.(*context.Context)).Errorf("%+v", err)
err = nil
@ -197,8 +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 where type = 0")
err = db.Instance.Select(&res, ssql)
err = db.Instance.Where("type=0 and status=0").Select("id").Table("email").Find(&res)
if err != nil && !errors.Is(err, sql.ErrNoRows) {
log.WithContext(session.Ctx.(*context.Context)).Errorf("SQL:%s Error: %+v", ssql, err)
@ -235,11 +234,9 @@ func (a action) List(session *gopop.Session, msg string) ([]gopop.MailInfo, erro
var ssql string
if listId != 0 {
ssql = db.WithContext(session.Ctx.(*context.Context), "SELECT id, ifnull(LENGTH(TEXT) , 0) + ifnull(LENGTH(html) , 0) AS `size` FROM email where id =?")
err = db.Instance.Select(&res, ssql, listId)
err = db.Instance.Select("id, ifnull(LENGTH(TEXT) , 0) + ifnull(LENGTH(html) , 0) AS `size`").Table("email").Where("id=?", listId).Find(&res)
} else {
ssql = db.WithContext(session.Ctx.(*context.Context), "SELECT id, ifnull(LENGTH(TEXT) , 0) + ifnull(LENGTH(html) , 0) AS `size` FROM email where type = 0")
err = db.Instance.Select(&res, ssql)
err = db.Instance.Select("id, ifnull(LENGTH(TEXT) , 0) + ifnull(LENGTH(html) , 0) AS `size`").Table("email").Where("type=0 and status=0").Find(&res)
}
if err != nil && !errors.Is(err, sql.ErrNoRows) {

View File

@ -9,6 +9,7 @@ import (
"pmail/dto/parsemail"
"pmail/hooks"
"pmail/http_server"
"pmail/models"
"pmail/pop3_server"
"pmail/services/setup/ssl"
"pmail/session"
@ -37,6 +38,7 @@ func Init(serverVersion string) {
if err != nil {
panic(err)
}
syncTables()
session.Init()
hooks.Init(serverVersion)
// smtp server start
@ -84,3 +86,26 @@ func dirInit() {
}
}
}
func syncTables() {
err := db.Instance.Sync2(&models.User{})
if err != nil {
panic(err)
}
err = db.Instance.Sync2(&models.Email{})
if err != nil {
panic(err)
}
err = db.Instance.Sync2(&models.Group{})
if err != nil {
panic(err)
}
err = db.Instance.Sync2(&models.Rule{})
if err != nil {
panic(err)
}
err = db.Instance.Sync2(&models.UserAuth{})
if err != nil {
panic(err)
}
}

View File

@ -14,7 +14,7 @@ func GetAttachments(ctx *context.Context, emailId int, cid string) (string, []by
// 获取邮件内容
var email models.Email
err := db.Instance.Get(&email, db.WithContext(ctx, "select * from email where id = ?"), emailId)
_, err := db.Instance.ID(emailId).Get(&email)
if err != nil {
log.WithContext(ctx).Errorf("SQL error:%+v", err)
return "", nil
@ -39,7 +39,7 @@ func GetAttachmentsByIndex(ctx *context.Context, emailId int, index int) (string
// 获取邮件内容
var email models.Email
err := db.Instance.Get(&email, db.WithContext(ctx, "select * from email where id = ?"), emailId)
_, err := db.Instance.ID(emailId).Get(&email)
if err != nil {
log.WithContext(ctx).Errorf("SQL error:%+v", err)
return "", nil

View File

@ -19,7 +19,7 @@ import (
func HasAuth(ctx *context.Context, email *models.Email) bool {
// 获取当前用户的auth
var auth []models.UserAuth
err := db.Instance.Select(&auth, db.WithContext(ctx, "select * from user_auth where user_id = ?"), ctx.UserID)
err := db.Instance.Where("user_id = ?", ctx.UserID).Find(&auth)
if err != nil {
log.WithContext(ctx).Errorf("SQL error:%+v", err)
return false

View File

@ -13,8 +13,10 @@ import (
func DelEmail(ctx *context.Context, ids []int) error {
var emails []*models.Email
db.Instance.Select(&emails, db.WithContext(ctx, fmt.Sprintf("select * from email where id in (%s)", array.Join(ids, ","))))
err := db.Instance.ID(ids).Find(&emails)
if err != nil {
return errors.Wrap(err)
}
for _, email := range emails {
// 检查是否有权限
hasAuth := auth.HasAuth(ctx, email)
@ -23,8 +25,7 @@ func DelEmail(ctx *context.Context, ids []int) error {
}
}
//_, err := db.Instance.Exec(db.WithContext(ctx, fmt.Sprintf("delete from email where id in (%s)", array.Join(ids, ","))))
_, err := db.Instance.Exec(db.WithContext(ctx, fmt.Sprintf("update email set status = 3 where id in (%s)", array.Join(ids, ","))))
_, err = db.Instance.Exec(db.WithContext(ctx, fmt.Sprintf("update email set status = 3 where id in (%s)", array.Join(ids, ","))))
if err != nil {
return errors.Wrap(err)
}

View File

@ -15,7 +15,7 @@ import (
func GetEmailDetail(ctx *context.Context, id int, markRead bool) (*models.Email, error) {
// 获取邮件内容
var email models.Email
err := db.Instance.Get(&email, db.WithContext(ctx, "select * from email where id = ?"), id)
_, err := db.Instance.ID(id).Get(&email)
if err != nil {
log.WithContext(ctx).Errorf("SQL error:%+v", err)
return nil, err

View File

@ -23,10 +23,7 @@ func DelGroup(ctx *context.Context, groupId int) (bool, error) {
allGroupIds = append(allGroupIds, groupId)
// 开启一个事务
trans, err := db.Instance.Begin()
if err != nil {
return false, errors.Wrap(err)
}
trans := db.Instance.NewSession()
res, err := trans.Exec(db.WithContext(ctx, fmt.Sprintf("delete from `group` where id in (%s) and user_id =?", array.Join(allGroupIds, ","))), ctx.UserID)
if err != nil {
@ -57,7 +54,10 @@ type id struct {
func getAllChildId(ctx *context.Context, rootId int) []int {
var ids []id
var ret []int
db.Instance.Select(&ids, db.WithContext(ctx, "select id from `group` where parent_id=? and user_id=?"), rootId, ctx.UserID)
err := db.Instance.Table("group").Where("parent_id=? and user_id=?", rootId, ctx.UserID).Find(&ids)
if err != nil {
log.WithContext(ctx).Errorf("getAllChildId err: %v", err)
}
for _, item := range ids {
ret = array.Merge(ret, getAllChildId(ctx, item.Id))
ret = append(ret, item.Id)
@ -89,7 +89,7 @@ func MoveMailToGroup(ctx *context.Context, mailId []int, groupId int) bool {
func buildChildren(ctx *context.Context, parentId int) []*GroupItem {
var ret []*GroupItem
var rootGroup []*models.Group
err := db.Instance.Select(&rootGroup, db.WithContext(ctx, "select * from `group` where parent_id=? and user_id=?"), parentId, ctx.UserID)
err := db.Instance.Table("group").Where("parent_id=? and user_id=?", parentId, ctx.UserID).Find(&rootGroup)
if err != nil {
log.WithContext(ctx).Errorf("SQL Error:%v", err)
@ -110,6 +110,6 @@ func buildChildren(ctx *context.Context, parentId int) []*GroupItem {
func GetGroupList(ctx *context.Context) []*models.Group {
var ret []*models.Group
db.Instance.Select(&ret, db.WithContext(ctx, "select * from `group` where user_id=?"), ctx.UserID)
db.Instance.Table("group").Where("user_id=?", ctx.UserID).Find(&ret)
return ret
}

View File

@ -9,17 +9,11 @@ import (
"pmail/utils/context"
)
func GetEmailList(ctx *context.Context, tag string, keyword string, offset, limit int) (emailList []*models.Email, total int) {
func GetEmailList(ctx *context.Context, tag string, keyword string, offset, limit int) (emailList []*models.Email, total int64) {
querySQL, queryParams := genSQL(ctx, false, tag, keyword, offset, limit)
counterSQL, counterParams := genSQL(ctx, true, tag, keyword, offset, limit)
querySQL, queryParams := genSQL(ctx, tag, keyword)
err := db.Instance.Select(&emailList, db.WithContext(ctx, querySQL), queryParams...)
if err != nil {
log.Errorf("SQL ERROR: %s ,Error:%s", querySQL, err)
}
err = db.Instance.Get(&total, db.WithContext(ctx, counterSQL), counterParams...)
total, err := db.Instance.Table("email").Where(querySQL, queryParams...).Desc("id").Limit(limit, offset).FindAndCount(&emailList)
if err != nil {
log.Errorf("SQL ERROR: %s ,Error:%s", querySQL, err)
}
@ -27,12 +21,9 @@ func GetEmailList(ctx *context.Context, tag string, keyword string, offset, limi
return
}
func genSQL(ctx *context.Context, counter bool, tag, keyword string, offset, limit int) (string, []any) {
func genSQL(ctx *context.Context, tag, keyword string) (string, []any) {
sql := "select * from email where 1=1 "
if counter {
sql = "select count(1) from email where 1=1 "
}
sql := "1=1 "
sqlParams := []any{}
@ -61,8 +52,5 @@ func genSQL(ctx *context.Context, counter bool, tag, keyword string, offset, lim
sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%")
}
sql += " order by id desc limit ? offset ?"
sqlParams = append(sqlParams, limit, offset)
return sql, sqlParams
}

View File

@ -18,9 +18,9 @@ func GetAllRules(ctx *context.Context) []*dto.Rule {
var res []*models.Rule
var err error
if ctx == nil || ctx.UserID == 0 {
err = db.Instance.Select(&res, "select * from rule order by sort desc")
err = db.Instance.Decr("sort").Find(&res)
} else {
err = db.Instance.Select(&res, db.WithContext(ctx, "select * from rule where user_id=? order by sort desc"), ctx.UserID)
err = db.Instance.Where("user_id=?", ctx.UserID).Decr("sort").Find(&res)
}
if err != nil {

View File

@ -29,7 +29,7 @@ func GetDatabaseSettings(ctx *context.Context) (string, string, error) {
func GetAdminPassword(ctx *context.Context) (string, error) {
users := []*models.User{}
err := db.Instance.Select(&users, "select * from user")
err := db.Instance.Find(&users)
if err != nil {
return "", errors.Wrap(err)
}

View File

@ -18,8 +18,8 @@ func Init() {
// 使用db存储session数据目前为了架构简单
// 暂不引入redis存储如果日后性能存在瓶颈可以将session迁移到redis
if config.Instance.DbType == "mysql" {
Instance.Store = mysqlstore.New(db.Instance.DB)
Instance.Store = mysqlstore.New(db.Instance.DB().DB)
} else {
Instance.Store = sqlite3store.New(db.Instance.DB)
Instance.Store = sqlite3store.New(db.Instance.DB().DB)
}
}

View File

@ -2,9 +2,11 @@ package smtp_server
import (
"bytes"
"database/sql"
"encoding/json"
"github.com/mileusna/spf"
log "github.com/sirupsen/logrus"
"github.com/spf13/cast"
"io"
"net"
"net/netip"
@ -13,6 +15,7 @@ import (
"pmail/dto/parsemail"
"pmail/hooks"
"pmail/hooks/framework"
"pmail/models"
"pmail/services/rule"
"pmail/utils/async"
"pmail/utils/context"
@ -83,12 +86,40 @@ func (s *Session) Data(r io.Reader) error {
}
// 转发
err := saveEmail(ctx, email, 1, true, true)
err := saveEmail(ctx, email, s.Ctx.UserID, 1, true, true)
if err != nil {
log.WithContext(ctx).Errorf("Email Save Error %v", err)
}
send.Send(ctx, email)
errMsg := ""
err, sendErr := send.Send(ctx, email)
log.WithContext(ctx).Debugf("插件执行--SendAfter")
as3 := async.New(ctx)
for _, hook := range hooks.HookList {
if hook == nil {
continue
}
as3.WaitProcess(func(hk any) {
hk.(framework.EmailHook).SendAfter(ctx, email, sendErr)
}, hook)
}
as3.Wait()
log.WithContext(ctx).Debugf("插件执行--SendAfter")
if err != nil {
errMsg = err.Error()
_, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =2 ,error=? where id = ? "), errMsg, email.MessageId)
if err != nil {
log.WithContext(ctx).Errorf("sql Error :%+v", err)
}
} else {
_, err := db.Instance.Exec(db.WithContext(ctx, "update email set status =1 where id = ? "), email.MessageId)
if err != nil {
log.WithContext(ctx).Errorf("sql Error :%+v", err)
}
}
} else {
// 收件
@ -121,7 +152,18 @@ func (s *Session) Data(r io.Reader) error {
return nil
}
saveEmail(ctx, email, 0, SPFStatus, dkimStatus)
// 垃圾过滤
if config.Instance.SpamFilterLevel == 1 && !SPFStatus && !dkimStatus {
log.WithContext(ctx).Infoln("垃圾邮件,拒信")
return nil
}
if config.Instance.SpamFilterLevel == 2 && !SPFStatus {
log.WithContext(ctx).Infoln("垃圾邮件,拒信")
return nil
}
saveEmail(ctx, email, 0, 0, SPFStatus, dkimStatus)
if email.MessageId > 0 {
log.WithContext(ctx).Debugf("开始执行邮件规则!")
@ -152,7 +194,7 @@ func (s *Session) Data(r io.Reader) error {
return nil
}
func saveEmail(ctx *context.Context, email *parsemail.Email, emailType int, SPFStatus, dkimStatus bool) error {
func saveEmail(ctx *context.Context, email *parsemail.Email, sendUserID int, emailType int, SPFStatus, dkimStatus bool) error {
var dkimV, spfV int8
if dkimStatus {
dkimV = 1
@ -161,52 +203,42 @@ func saveEmail(ctx *context.Context, email *parsemail.Email, emailType int, SPFS
spfV = 1
}
// 垃圾过滤
if config.Instance.SpamFilterLevel == 1 && !SPFStatus && !dkimStatus {
log.WithContext(ctx).Infoln("垃圾邮件,拒信")
return nil
}
if config.Instance.SpamFilterLevel == 2 && !SPFStatus {
log.WithContext(ctx).Infoln("垃圾邮件,拒信")
return nil
}
log.WithContext(ctx).Debugf("开始入库!")
if email == nil {
return nil
}
sql := "INSERT INTO email (type, send_date, subject, reply_to, from_name, from_address, `to`, bcc, cc, text, html, sender, attachments,spf_check, dkim_check, create_time,is_read,status,group_id) VALUES (?,?,?,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
res, err := db.Instance.Exec(sql,
emailType,
email.Date,
email.Subject,
json2string(email.ReplyTo),
email.From.Name,
email.From.EmailAddress,
json2string(email.To),
json2string(email.Bcc),
json2string(email.Cc),
email.Text,
email.HTML,
json2string(email.Sender),
json2string(email.Attachments),
spfV,
dkimV,
time.Now(),
email.IsRead,
email.Status,
email.GroupId,
)
modelEmail := models.Email{
Type: cast.ToInt8(emailType),
GroupId: email.GroupId,
Subject: email.Subject,
ReplyTo: json2string(email.ReplyTo),
FromName: email.From.Name,
FromAddress: email.From.EmailAddress,
To: json2string(email.To),
Bcc: json2string(email.Bcc),
Cc: json2string(email.Cc),
Text: sql.NullString{String: string(email.Text), Valid: true},
Html: sql.NullString{String: string(email.HTML), Valid: true},
Sender: json2string(email.Sender),
Attachments: json2string(email.Attachments),
SPFCheck: spfV,
DKIMCheck: dkimV,
SendUserID: sendUserID,
SendDate: time.Now(),
Status: cast.ToInt8(email.Status),
CreateTime: time.Now(),
}
_, err := db.Instance.Insert(&modelEmail)
if err != nil {
log.WithContext(ctx).Errorf("db insert error:%+v", err.Error())
}
insertId, _ := res.LastInsertId()
if insertId > 0 {
email.MessageId = insertId
if modelEmail.Id > 0 {
email.MessageId = cast.ToInt64(modelEmail.Id)
}
return nil

View File

@ -81,8 +81,7 @@ func (s *Session) AuthPlain(username, pwd string) error {
username = infos[0]
}
err := db.Instance.Get(&user, db.WithContext(s.Ctx, "select * from user where account =? and password =?"),
username, encodePwd)
_, err := db.Instance.Where("account =? and password =?", username, encodePwd).Get(&user)
if err != nil && err != sql.ErrNoRows {
log.Errorf("%+v", err)
}