initial cc support
This commit is contained in:
@@ -25,8 +25,10 @@ const (
|
||||
eventReferencesKey = "cc.etke.postmoogle.references"
|
||||
eventInReplyToKey = "cc.etke.postmoogle.inReplyTo"
|
||||
eventSubjectKey = "cc.etke.postmoogle.subject"
|
||||
eventRcptToKey = "cc.etke.postmoogle.rcptTo"
|
||||
eventFromKey = "cc.etke.postmoogle.from"
|
||||
eventToKey = "cc.etke.postmoogle.to"
|
||||
eventCcKey = "cc.etke.postmoogle.cc"
|
||||
)
|
||||
|
||||
// SetSendmail sets mail sending func to the bot
|
||||
|
||||
@@ -152,7 +152,9 @@ func (s roomSettings) ContentOptions() *utils.ContentOptions {
|
||||
Threads: !s.NoThreads(),
|
||||
|
||||
ToKey: eventToKey,
|
||||
CcKey: eventCcKey,
|
||||
FromKey: eventFromKey,
|
||||
RcptToKey: eventRcptToKey,
|
||||
SubjectKey: eventSubjectKey,
|
||||
MessageIDKey: eventMessageIDkey,
|
||||
InReplyToKey: eventInReplyToKey,
|
||||
|
||||
@@ -60,6 +60,7 @@ func (m *mailServer) Login(state *smtp.ConnectionState, username, password strin
|
||||
from: username,
|
||||
log: m.log,
|
||||
domains: m.domains,
|
||||
tos: []string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -80,6 +81,7 @@ func (m *mailServer) AnonymousLogin(state *smtp.ConnectionState) (smtp.Session,
|
||||
log: m.log,
|
||||
domains: m.domains,
|
||||
addr: state.RemoteAddr,
|
||||
tos: []string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ type incomingSession struct {
|
||||
|
||||
ctx context.Context
|
||||
addr net.Addr
|
||||
to string
|
||||
tos []string
|
||||
from string
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ func (s *incomingSession) Mail(from string, opts smtp.MailOptions) error {
|
||||
|
||||
func (s *incomingSession) Rcpt(to string) error {
|
||||
sentry.GetHubFromContext(s.ctx).Scope().SetTag("to", to)
|
||||
s.to = to
|
||||
s.tos = append(s.tos, to)
|
||||
var domainok bool
|
||||
for _, domain := range s.domains {
|
||||
if utils.Hostname(to) == domain {
|
||||
@@ -66,7 +66,7 @@ func (s *incomingSession) Rcpt(to string) error {
|
||||
}
|
||||
|
||||
validations := s.getFilters(roomID)
|
||||
if !validateEmail(s.from, s.to, s.log, validations) {
|
||||
if !validateEmail(s.from, to, s.log, validations) {
|
||||
s.ban(s.addr)
|
||||
return ErrBanned
|
||||
}
|
||||
@@ -89,20 +89,15 @@ func (s *incomingSession) Data(r io.Reader) error {
|
||||
return err
|
||||
}
|
||||
|
||||
files := parseAttachments(eml.Attachments, s.log)
|
||||
|
||||
email := utils.NewEmail(
|
||||
eml.GetHeader("Message-Id"),
|
||||
eml.GetHeader("In-Reply-To"),
|
||||
eml.GetHeader("References"),
|
||||
eml.GetHeader("Subject"),
|
||||
s.from,
|
||||
s.to,
|
||||
eml.Text,
|
||||
eml.HTML,
|
||||
files)
|
||||
|
||||
return s.receiveEmail(s.ctx, email)
|
||||
email := utils.FromEnvelope(s.tos[0], eml)
|
||||
for _, to := range s.tos {
|
||||
email.RcptTo = to
|
||||
err := s.receiveEmail(s.ctx, email)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (s *incomingSession) Reset() {}
|
||||
func (s *incomingSession) Logout() error { return nil }
|
||||
@@ -115,7 +110,7 @@ type outgoingSession struct {
|
||||
domains []string
|
||||
|
||||
ctx context.Context
|
||||
to string
|
||||
tos []string
|
||||
from string
|
||||
}
|
||||
|
||||
@@ -129,7 +124,7 @@ func (s *outgoingSession) Mail(from string, opts smtp.MailOptions) error {
|
||||
|
||||
func (s *outgoingSession) Rcpt(to string) error {
|
||||
sentry.GetHubFromContext(s.ctx).Scope().SetTag("to", to)
|
||||
s.to = to
|
||||
s.tos = append(s.tos, to)
|
||||
|
||||
s.log.Debug("mail to %s", to)
|
||||
return nil
|
||||
@@ -141,21 +136,16 @@ func (s *outgoingSession) Data(r io.Reader) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
email := utils.FromEnvelope(s.tos[0], eml)
|
||||
for _, to := range s.tos {
|
||||
email.RcptTo = to
|
||||
err := s.sendmail(email.From, to, email.Compose(s.privkey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
files := parseAttachments(eml.Attachments, s.log)
|
||||
|
||||
email := utils.NewEmail(
|
||||
eml.GetHeader("Message-Id"),
|
||||
eml.GetHeader("In-Reply-To"),
|
||||
eml.GetHeader("References"),
|
||||
eml.GetHeader("Subject"),
|
||||
s.from,
|
||||
s.to,
|
||||
eml.Text,
|
||||
eml.HTML,
|
||||
files)
|
||||
|
||||
return s.sendmail(email.From, email.To, email.Compose(s.privkey))
|
||||
return nil
|
||||
}
|
||||
func (s *outgoingSession) Reset() {}
|
||||
func (s *outgoingSession) Logout() error { return nil }
|
||||
@@ -170,16 +160,3 @@ func validateEmail(from, to string, log *logger.Logger, options utils.IncomingFi
|
||||
|
||||
return v.Email(from)
|
||||
}
|
||||
|
||||
func parseAttachments(parts []*enmime.Part, log *logger.Logger) []*utils.File {
|
||||
files := make([]*utils.File, 0, len(parts))
|
||||
for _, attachment := range parts {
|
||||
for _, err := range attachment.Errors {
|
||||
log.Warn("attachment error: %v", err)
|
||||
}
|
||||
file := utils.NewFile(attachment.FileName, attachment.Content)
|
||||
files = append(files, file)
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ type Email struct {
|
||||
References string
|
||||
From string
|
||||
To string
|
||||
RcptTo string
|
||||
CC string
|
||||
Subject string
|
||||
Text string
|
||||
HTML string
|
||||
@@ -56,6 +58,8 @@ type ContentOptions struct {
|
||||
SubjectKey string
|
||||
FromKey string
|
||||
ToKey string
|
||||
CcKey string
|
||||
RcptToKey string
|
||||
}
|
||||
|
||||
// AddressValid checks if email address is valid
|
||||
@@ -64,6 +68,16 @@ func AddressValid(email string) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// EmailDate returns Date in RFC1123 with numeric timezone
|
||||
func EmailDate(original ...time.Time) string {
|
||||
now := time.Now().UTC()
|
||||
if len(original) > 0 && !original[0].IsZero() {
|
||||
now = original[0]
|
||||
}
|
||||
|
||||
return now.Format(time.RFC1123Z)
|
||||
}
|
||||
|
||||
// MessageID generates email Message-Id from matrix event ID
|
||||
func MessageID(eventID id.EventID, domain string) string {
|
||||
return fmt.Sprintf("<%s@%s>", eventID, domain)
|
||||
@@ -72,12 +86,13 @@ func MessageID(eventID id.EventID, domain string) string {
|
||||
// NewEmail constructs Email object
|
||||
func NewEmail(messageID, inReplyTo, references, subject, from, to, text, html string, files []*File) *Email {
|
||||
email := &Email{
|
||||
Date: time.Now().UTC().Format(time.RFC1123Z),
|
||||
Date: EmailDate(),
|
||||
MessageID: messageID,
|
||||
InReplyTo: inReplyTo,
|
||||
References: references,
|
||||
From: from,
|
||||
To: to,
|
||||
RcptTo: to,
|
||||
Subject: subject,
|
||||
Text: text,
|
||||
HTML: html,
|
||||
@@ -92,10 +107,46 @@ func NewEmail(messageID, inReplyTo, references, subject, from, to, text, html st
|
||||
return email
|
||||
}
|
||||
|
||||
func FromEnvelope(rcptto string, eml *enmime.Envelope) *Email {
|
||||
datetime, _ := eml.Date() //nolint:errcheck // handled in EmailDate()
|
||||
date := EmailDate(datetime)
|
||||
|
||||
var html string
|
||||
if eml.HTML != "" {
|
||||
html = styleRegex.ReplaceAllString(eml.HTML, "")
|
||||
}
|
||||
|
||||
files := make([]*File, 0, len(eml.Attachments))
|
||||
for _, attachment := range eml.Attachments {
|
||||
for _, err := range attachment.Errors {
|
||||
log.Warn("attachment error: %v", err)
|
||||
}
|
||||
file := NewFile(attachment.FileName, attachment.Content)
|
||||
files = append(files, file)
|
||||
}
|
||||
|
||||
email := &Email{
|
||||
Date: date,
|
||||
MessageID: eml.GetHeader("Message-Id"),
|
||||
InReplyTo: eml.GetHeader("In-Reply-To"),
|
||||
References: eml.GetHeader("References"),
|
||||
From: eml.GetHeader("From"),
|
||||
To: eml.GetHeader("To"),
|
||||
RcptTo: rcptto,
|
||||
CC: eml.GetHeader("Cc"),
|
||||
Subject: eml.GetHeader("Subject"),
|
||||
Text: eml.Text,
|
||||
HTML: html,
|
||||
Files: files,
|
||||
}
|
||||
|
||||
return email
|
||||
}
|
||||
|
||||
// Mailbox returns postmoogle's mailbox, parsing it from FROM (if incoming=false) or TO (incoming=true)
|
||||
func (e *Email) Mailbox(incoming bool) string {
|
||||
if incoming {
|
||||
return Mailbox(e.To)
|
||||
return Mailbox(e.RcptTo)
|
||||
}
|
||||
return Mailbox(e.From)
|
||||
}
|
||||
@@ -133,8 +184,10 @@ func (e *Email) Content(threadID id.EventID, options *ContentOptions) *event.Con
|
||||
options.InReplyToKey: e.InReplyTo,
|
||||
options.ReferencesKey: e.References,
|
||||
options.SubjectKey: e.Subject,
|
||||
options.RcptToKey: e.RcptTo,
|
||||
options.FromKey: e.From,
|
||||
options.ToKey: e.To,
|
||||
options.CcKey: e.CC,
|
||||
},
|
||||
Parsed: &parsed,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user