mirror of
https://github.com/Jinnrry/PMail.git
synced 2025-09-27 11:42:19 +08:00
3
docs/debug.md
Normal file
3
docs/debug.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
测试imap协议返回
|
||||||
|
|
||||||
|
`openssl s_client -crlf -connect imap.xxxx.com:993`
|
@@ -65,9 +65,9 @@ func Init(version string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Instance.LogLevel == "debug" {
|
//if config.Instance.LogLevel == "debug" {
|
||||||
Instance.ShowSQL(true)
|
// Instance.ShowSQL(true)
|
||||||
}
|
//}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -2,6 +2,7 @@ package parsemail
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/Jinnrry/pmail/config"
|
"github.com/Jinnrry/pmail/config"
|
||||||
@@ -10,9 +11,9 @@ import (
|
|||||||
"github.com/emersion/go-message"
|
"github.com/emersion/go-message"
|
||||||
_ "github.com/emersion/go-message/charset"
|
_ "github.com/emersion/go-message/charset"
|
||||||
"github.com/emersion/go-message/mail"
|
"github.com/emersion/go-message/mail"
|
||||||
|
"github.com/microcosm-cc/bluemonday"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
"github.com/microcosm-cc/bluemonday"
|
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
@@ -141,7 +142,6 @@ func sanitizeHTML(htmlContent string) string {
|
|||||||
return sanitized
|
return sanitized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Sanitize Text
|
// Sanitize Text
|
||||||
func sanitizeText(text string) string {
|
func sanitizeText(text string) string {
|
||||||
return strictPolicy.Sanitize(text)
|
return strictPolicy.Sanitize(text)
|
||||||
@@ -360,7 +360,6 @@ func buildUser(str string) *User {
|
|||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func buildUsers(strs []string) []*User {
|
func buildUsers(strs []string) []*User {
|
||||||
var ret []*User
|
var ret []*User
|
||||||
for _, line := range strs {
|
for _, line := range strs {
|
||||||
@@ -461,6 +460,33 @@ func (e *Email) ForwardBuildBytes(ctx *context.Context, sender *models.User) []b
|
|||||||
return instance.Sign(b.String())
|
return instance.Sign(b.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Email) BuildPart(ctx *context.Context, loc []int) []byte {
|
||||||
|
if len(loc) < 2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if loc[0] == 1 && loc[1] == 2 {
|
||||||
|
|
||||||
|
encoded := base64.StdEncoding.EncodeToString(e.HTML)
|
||||||
|
encoded += "\r\n"
|
||||||
|
|
||||||
|
return []byte(encoded)
|
||||||
|
}
|
||||||
|
if loc[0] == 1 && loc[1] == 1 {
|
||||||
|
if len(e.Text) == 0 {
|
||||||
|
encoded := base64.StdEncoding.EncodeToString(e.HTML)
|
||||||
|
encoded += "\r\n"
|
||||||
|
|
||||||
|
return []byte(encoded)
|
||||||
|
}
|
||||||
|
encoded := base64.StdEncoding.EncodeToString(e.Text)
|
||||||
|
encoded += "\r\n"
|
||||||
|
|
||||||
|
return []byte(encoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Email) BuildBytes(ctx *context.Context, dkim bool) []byte {
|
func (e *Email) BuildBytes(ctx *context.Context, dkim bool) []byte {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
|
||||||
@@ -513,6 +539,8 @@ func (e *Email) BuildBytes(ctx *context.Context, dkim bool) []byte {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithContext(ctx).Fatal(err)
|
log.WithContext(ctx).Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(e.Text) > 0 {
|
||||||
var th mail.InlineHeader
|
var th mail.InlineHeader
|
||||||
th.Header.Set("Content-Transfer-Encoding", "base64")
|
th.Header.Set("Content-Transfer-Encoding", "base64")
|
||||||
th.SetContentType("text/plain", map[string]string{
|
th.SetContentType("text/plain", map[string]string{
|
||||||
@@ -524,13 +552,14 @@ func (e *Email) BuildBytes(ctx *context.Context, dkim bool) []byte {
|
|||||||
}
|
}
|
||||||
io.WriteString(w, string(e.Text))
|
io.WriteString(w, string(e.Text))
|
||||||
w.Close()
|
w.Close()
|
||||||
|
}
|
||||||
|
|
||||||
var html mail.InlineHeader
|
var html mail.InlineHeader
|
||||||
html.SetContentType("text/html", map[string]string{
|
html.SetContentType("text/html", map[string]string{
|
||||||
"charset": "UTF-8",
|
"charset": "UTF-8",
|
||||||
})
|
})
|
||||||
html.Header.Set("Content-Transfer-Encoding", "base64")
|
html.Header.Set("Content-Transfer-Encoding", "base64")
|
||||||
w, err = tw.CreatePart(html)
|
w, err := tw.CreatePart(html)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/emersion/go-message"
|
"github.com/emersion/go-message"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -84,3 +85,13 @@ func TestEmail_builder(t *testing.T) {
|
|||||||
rest := e.BuildBytes(nil, false)
|
rest := e.BuildBytes(nil, false)
|
||||||
fmt.Println(string(rest))
|
fmt.Println(string(rest))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEmail_BuildPart(t *testing.T) {
|
||||||
|
e := Email{
|
||||||
|
Text: []byte("text"),
|
||||||
|
HTML: []byte("html"),
|
||||||
|
}
|
||||||
|
res := e.BuildPart(nil, []int{1, 2})
|
||||||
|
fmt.Println(string(res))
|
||||||
|
|
||||||
|
}
|
||||||
|
@@ -17,6 +17,7 @@ require (
|
|||||||
github.com/go-acme/lego/v4 v4.23.1
|
github.com/go-acme/lego/v4 v4.23.1
|
||||||
github.com/go-sql-driver/mysql v1.9.2
|
github.com/go-sql-driver/mysql v1.9.2
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
github.com/mileusna/spf v0.9.5
|
github.com/mileusna/spf v0.9.5
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/spf13/cast v1.7.1
|
github.com/spf13/cast v1.7.1
|
||||||
@@ -39,7 +40,6 @@ require (
|
|||||||
github.com/gorilla/css v1.0.1 // indirect
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
|
|
||||||
github.com/miekg/dns v1.1.65 // indirect
|
github.com/miekg/dns v1.1.65 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
@@ -42,14 +42,131 @@ func (s *serverSession) Fetch(w *imapserver.FetchWriter, numSet imap.NumSet, opt
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 纯文本 text/plain
|
||||||
|
func bsTextPlain(size uint32, numLines int64) *imap.BodyStructureSinglePart {
|
||||||
|
return &imap.BodyStructureSinglePart{
|
||||||
|
Type: "text",
|
||||||
|
Subtype: "plain",
|
||||||
|
Params: map[string]string{"charset": "utf-8"},
|
||||||
|
Encoding: "base64",
|
||||||
|
Size: size, // 按字节数
|
||||||
|
Text: &imap.BodyStructureText{NumLines: numLines},
|
||||||
|
Extended: &imap.BodyStructureSinglePartExt{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTML text/html
|
||||||
|
func bsTextHTML(size uint32, numLines int64) *imap.BodyStructureSinglePart {
|
||||||
|
return &imap.BodyStructureSinglePart{
|
||||||
|
Type: "text",
|
||||||
|
Subtype: "html",
|
||||||
|
Params: map[string]string{"charset": "utf-8"},
|
||||||
|
Encoding: "base64",
|
||||||
|
Size: size,
|
||||||
|
Text: &imap.BodyStructureText{NumLines: numLines},
|
||||||
|
Extended: &imap.BodyStructureSinglePartExt{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用附件(传入 MIME,如 "application/pdf")
|
||||||
|
func bsAttachment(filename, mime string, size uint32, encoding string) *imap.BodyStructureSinglePart {
|
||||||
|
mt, st := "application", "octet-stream"
|
||||||
|
if slash := strings.IndexByte(mime, '/'); slash > 0 {
|
||||||
|
mt, st = mime[:slash], mime[slash+1:]
|
||||||
|
}
|
||||||
|
return &imap.BodyStructureSinglePart{
|
||||||
|
Type: mt,
|
||||||
|
Subtype: st,
|
||||||
|
Params: map[string]string{"name": filename}, // 备用名
|
||||||
|
ID: "", // 可填 Content-ID
|
||||||
|
Encoding: encoding, // 常见 "base64"
|
||||||
|
Size: size,
|
||||||
|
Extended: &imap.BodyStructureSinglePartExt{
|
||||||
|
Disposition: &imap.BodyStructureDisposition{
|
||||||
|
Value: "attachment",
|
||||||
|
Params: map[string]string{"filename": filename}, // 客户端优先用这里
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// multipart/alternative:text + html
|
||||||
|
func bsAlternative(text, html *imap.BodyStructureSinglePart) *imap.BodyStructureMultiPart {
|
||||||
|
if text == nil && html == nil {
|
||||||
|
return &imap.BodyStructureMultiPart{
|
||||||
|
Subtype: "alternative",
|
||||||
|
Children: []imap.BodyStructure{},
|
||||||
|
Extended: &imap.BodyStructureMultiPartExt{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if text == nil {
|
||||||
|
return &imap.BodyStructureMultiPart{
|
||||||
|
Subtype: "alternative",
|
||||||
|
Children: []imap.BodyStructure{html},
|
||||||
|
Extended: &imap.BodyStructureMultiPartExt{}, // 可选:Params/Disposition/Language/Location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if html == nil {
|
||||||
|
return &imap.BodyStructureMultiPart{
|
||||||
|
Subtype: "alternative",
|
||||||
|
Children: []imap.BodyStructure{text},
|
||||||
|
Extended: &imap.BodyStructureMultiPartExt{}, // 可选:Params/Disposition/Language/Location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &imap.BodyStructureMultiPart{
|
||||||
|
Subtype: "alternative",
|
||||||
|
Children: []imap.BodyStructure{text, html},
|
||||||
|
Extended: &imap.BodyStructureMultiPartExt{}, // 可选:Params/Disposition/Language/Location
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// multipart/mixed:{ alternative(text+html), attachments... }
|
||||||
|
func bsMixedWithAttachments(alt *imap.BodyStructureMultiPart, extend bool, atts ...imap.BodyStructure) *imap.BodyStructureMultiPart {
|
||||||
|
children := []imap.BodyStructure{alt}
|
||||||
|
children = append(children, atts...)
|
||||||
|
var ext *imap.BodyStructureMultiPartExt
|
||||||
|
if extend {
|
||||||
|
ext = &imap.BodyStructureMultiPartExt{}
|
||||||
|
}
|
||||||
|
return &imap.BodyStructureMultiPart{
|
||||||
|
Subtype: "mixed",
|
||||||
|
Children: children,
|
||||||
|
Extended: ext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func write(ctx *context.Context, w *imapserver.FetchWriter, emailList []*response.EmailResponseData, options *imap.FetchOptions) {
|
func write(ctx *context.Context, w *imapserver.FetchWriter, emailList []*response.EmailResponseData, options *imap.FetchOptions) {
|
||||||
for _, email := range emailList {
|
for _, email := range emailList {
|
||||||
writer := w.CreateMessage(cast.ToUint32(email.SerialNumber))
|
writer := w.CreateMessage(cast.ToUint32(email.SerialNumber))
|
||||||
|
|
||||||
|
traEmail := parsemail.NewEmailFromModel(email.Email)
|
||||||
|
|
||||||
if options.UID {
|
if options.UID {
|
||||||
writer.WriteUID(imap.UID(email.UeId))
|
writer.WriteUID(imap.UID(email.UeId))
|
||||||
}
|
}
|
||||||
|
if options.BodyStructure != nil {
|
||||||
|
var html, text *imap.BodyStructureSinglePart
|
||||||
|
if len(traEmail.HTML) > 0 {
|
||||||
|
html = bsTextHTML(uint32(len(traEmail.HTML)), int64(bytes.Count(traEmail.HTML, []byte("\n"))+1))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(traEmail.Text) > 0 {
|
||||||
|
text = bsTextPlain(uint32(len(traEmail.Text)), int64(bytes.Count(traEmail.Text, []byte("\n"))+1))
|
||||||
|
}
|
||||||
|
|
||||||
|
alt := bsAlternative(text, html)
|
||||||
|
|
||||||
|
var attrs []imap.BodyStructure
|
||||||
|
for _, attachment := range traEmail.Attachments {
|
||||||
|
attrs = append(attrs, bsAttachment(attachment.Filename, attachment.ContentType, uint32(len(attachment.Content)), "base64"))
|
||||||
|
}
|
||||||
|
bs := bsMixedWithAttachments(alt, options.BodyStructure.Extended, attrs...) // 最终的 BodyStructure(接口值)
|
||||||
|
|
||||||
|
writer.WriteBodyStructure(bs)
|
||||||
|
}
|
||||||
if options.RFC822Size {
|
if options.RFC822Size {
|
||||||
emailContent := parsemail.NewEmailFromModel(email.Email).BuildBytes(ctx, false)
|
emailContent := traEmail.BuildBytes(ctx, false)
|
||||||
writer.WriteRFC822Size(cast.ToInt64(len(emailContent)))
|
writer.WriteRFC822Size(cast.ToInt64(len(emailContent)))
|
||||||
}
|
}
|
||||||
if options.Flags {
|
if options.Flags {
|
||||||
@@ -66,16 +183,22 @@ func write(ctx *context.Context, w *imapserver.FetchWriter, emailList []*respons
|
|||||||
if !section.Peek {
|
if !section.Peek {
|
||||||
detail.MakeRead(ctx, email.Id, true)
|
detail.MakeRead(ctx, email.Id, true)
|
||||||
}
|
}
|
||||||
emailContent := parsemail.NewEmailFromModel(email.Email).BuildBytes(ctx, false)
|
emailContent := traEmail.BuildBytes(ctx, false)
|
||||||
|
|
||||||
if section.Specifier == imap.PartSpecifierNone || section.Specifier == imap.PartSpecifierText {
|
if section.Specifier == imap.PartSpecifierNone || section.Specifier == imap.PartSpecifierText {
|
||||||
|
if len(section.Part) == 2 {
|
||||||
|
// 取text部分
|
||||||
|
bodyWriter := writer.WriteBodySection(section, cast.ToInt64(len(emailContent)))
|
||||||
|
bodyWriter.Write(traEmail.BuildPart(ctx, section.Part))
|
||||||
|
bodyWriter.Close()
|
||||||
|
} else {
|
||||||
bodyWriter := writer.WriteBodySection(section, cast.ToInt64(len(emailContent)))
|
bodyWriter := writer.WriteBodySection(section, cast.ToInt64(len(emailContent)))
|
||||||
bodyWriter.Write(emailContent)
|
bodyWriter.Write(emailContent)
|
||||||
bodyWriter.Close()
|
bodyWriter.Close()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if section.Specifier == imap.PartSpecifierHeader {
|
if section.Specifier == imap.PartSpecifierHeader {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
parseEmail := parsemail.NewEmailFromModel(email.Email)
|
|
||||||
fields := section.HeaderFields
|
fields := section.HeaderFields
|
||||||
|
|
||||||
if fields == nil || len(fields) == 0 {
|
if fields == nil || len(fields) == 0 {
|
||||||
@@ -97,10 +220,10 @@ func write(ctx *context.Context, w *imapserver.FetchWriter, emailList []*respons
|
|||||||
fmt.Fprintf(&b, "From: %s\r\n", email.FromAddress)
|
fmt.Fprintf(&b, "From: %s\r\n", email.FromAddress)
|
||||||
}
|
}
|
||||||
case "to":
|
case "to":
|
||||||
fmt.Fprintf(&b, "To: %s\r\n", parseEmail.BuildTo2String())
|
fmt.Fprintf(&b, "To: %s\r\n", traEmail.BuildTo2String())
|
||||||
case "cc":
|
case "cc":
|
||||||
if len(parseEmail.Cc) > 0 {
|
if len(traEmail.Cc) > 0 {
|
||||||
fmt.Fprintf(&b, "Cc: %s\r\n", parseEmail.BuildCc2String())
|
fmt.Fprintf(&b, "Cc: %s\r\n", traEmail.BuildCc2String())
|
||||||
}
|
}
|
||||||
case "message-id":
|
case "message-id":
|
||||||
fmt.Fprintf(&b, "Message-ID: %s\r\n", fmt.Sprintf("%d@%s", email.Id, config.Instance.Domain))
|
fmt.Fprintf(&b, "Message-ID: %s\r\n", fmt.Sprintf("%d@%s", email.Id, config.Instance.Domain))
|
||||||
|
@@ -11,12 +11,18 @@ import (
|
|||||||
func (s *serverSession) Search(kind imapserver.NumKind, criteria *imap.SearchCriteria, options *imap.SearchOptions) (*imap.SearchData, error) {
|
func (s *serverSession) Search(kind imapserver.NumKind, criteria *imap.SearchCriteria, options *imap.SearchOptions) (*imap.SearchData, error) {
|
||||||
retList := []*response.UserEmailUIDData{}
|
retList := []*response.UserEmailUIDData{}
|
||||||
|
|
||||||
|
if len(criteria.UID) > 0 {
|
||||||
for _, uidSet := range criteria.UID {
|
for _, uidSet := range criteria.UID {
|
||||||
for _, uid := range uidSet {
|
for _, uid := range uidSet {
|
||||||
res := list.GetUEListByUID(s.ctx, s.currentMailbox, cast.ToInt(uint32(uid.Start)), cast.ToInt(uint32(uid.Stop)), nil)
|
res := list.GetUEListByUID(s.ctx, s.currentMailbox, cast.ToInt(uint32(uid.Start)), cast.ToInt(uint32(uid.Stop)), nil)
|
||||||
retList = append(retList, res...)
|
retList = append(retList, res...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
res := list.GetUEListByUID(s.ctx, s.currentMailbox, 0, 0, nil)
|
||||||
|
retList = append(retList, res...)
|
||||||
|
}
|
||||||
|
|
||||||
ret := &imap.SearchData{}
|
ret := &imap.SearchData{}
|
||||||
|
|
||||||
if kind == imapserver.NumKindSeq {
|
if kind == imapserver.NumKindSeq {
|
||||||
|
@@ -2,10 +2,10 @@ package smtp_server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"github.com/Jinnrry/pmail/db"
|
"github.com/Jinnrry/pmail/db"
|
||||||
"github.com/Jinnrry/pmail/models"
|
"github.com/Jinnrry/pmail/models"
|
||||||
"github.com/Jinnrry/pmail/utils/context"
|
"github.com/Jinnrry/pmail/utils/context"
|
||||||
"github.com/Jinnrry/pmail/utils/errors"
|
|
||||||
"github.com/Jinnrry/pmail/utils/id"
|
"github.com/Jinnrry/pmail/utils/id"
|
||||||
"github.com/Jinnrry/pmail/utils/password"
|
"github.com/Jinnrry/pmail/utils/password"
|
||||||
"github.com/emersion/go-sasl"
|
"github.com/emersion/go-sasl"
|
||||||
|
@@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
oerrors "errors"
|
||||||
"github.com/Jinnrry/pmail/config"
|
"github.com/Jinnrry/pmail/config"
|
||||||
"github.com/Jinnrry/pmail/db"
|
"github.com/Jinnrry/pmail/db"
|
||||||
"github.com/Jinnrry/pmail/dto/parsemail"
|
"github.com/Jinnrry/pmail/dto/parsemail"
|
||||||
@@ -15,7 +16,6 @@ import (
|
|||||||
"github.com/Jinnrry/pmail/utils/array"
|
"github.com/Jinnrry/pmail/utils/array"
|
||||||
"github.com/Jinnrry/pmail/utils/async"
|
"github.com/Jinnrry/pmail/utils/async"
|
||||||
"github.com/Jinnrry/pmail/utils/context"
|
"github.com/Jinnrry/pmail/utils/context"
|
||||||
"github.com/Jinnrry/pmail/utils/errors"
|
|
||||||
"github.com/Jinnrry/pmail/utils/send"
|
"github.com/Jinnrry/pmail/utils/send"
|
||||||
"github.com/mileusna/spf"
|
"github.com/mileusna/spf"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -69,7 +69,7 @@ func (s *Session) Data(r io.Reader) error {
|
|||||||
if s.Ctx.UserID > 0 {
|
if s.Ctx.UserID > 0 {
|
||||||
account, _ := email.From.GetDomainAccount()
|
account, _ := email.From.GetDomainAccount()
|
||||||
if account != ctx.UserAccount && !ctx.IsAdmin {
|
if account != ctx.UserAccount && !ctx.IsAdmin {
|
||||||
return errors.New("No Auth")
|
return oerrors.New("No Auth")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithContext(ctx).Debugf("开始执行插件SendBefore!")
|
log.WithContext(ctx).Debugf("开始执行插件SendBefore!")
|
||||||
|
Reference in New Issue
Block a user