make thread replies CC-aware and multi-domain aware
This commit is contained in:
@@ -438,7 +438,7 @@ func (b *Bot) runSend(ctx context.Context) {
|
|||||||
from := mailbox + "@" + domain
|
from := mailbox + "@" + domain
|
||||||
ID := email.MessageID(evt.ID, domain)
|
ID := email.MessageID(evt.ID, domain)
|
||||||
for _, to := range tos {
|
for _, to := range tos {
|
||||||
eml := email.New(ID, "", " "+ID, subject, from, to, body, htmlBody, nil)
|
eml := email.New(ID, "", " "+ID, subject, from, to, to, "", body, htmlBody, nil)
|
||||||
data := eml.Compose(b.getBotSettings().DKIMPrivateKey())
|
data := eml.Compose(b.getBotSettings().DKIMPrivateKey())
|
||||||
if data == "" {
|
if data == "" {
|
||||||
b.SendError(ctx, evt.RoomID, "email body is empty")
|
b.SendError(ctx, evt.RoomID, "email body is empty")
|
||||||
|
|||||||
49
bot/email.go
49
bot/email.go
@@ -155,13 +155,8 @@ func (b *Bot) SendEmailReply(ctx context.Context) {
|
|||||||
b.lock(evt.RoomID.String())
|
b.lock(evt.RoomID.String())
|
||||||
defer b.unlock(evt.RoomID.String())
|
defer b.unlock(evt.RoomID.String())
|
||||||
|
|
||||||
fromMailbox := mailbox + "@" + domain
|
|
||||||
meta := b.getParentEmail(evt, domain)
|
meta := b.getParentEmail(evt, domain)
|
||||||
// when email was sent from matrix and reply was sent from matrix again
|
meta.fixtofrom(mailbox, domain, b.domains)
|
||||||
if fromMailbox != meta.From {
|
|
||||||
meta.To = meta.From
|
|
||||||
}
|
|
||||||
meta.From = fromMailbox
|
|
||||||
|
|
||||||
if meta.To == "" {
|
if meta.To == "" {
|
||||||
b.Error(ctx, evt.RoomID, "cannot find parent email and continue the thread. Please, start a new email thread")
|
b.Error(ctx, evt.RoomID, "cannot find parent email and continue the thread. Please, start a new email thread")
|
||||||
@@ -181,7 +176,7 @@ func (b *Bot) SendEmailReply(ctx context.Context) {
|
|||||||
meta.MessageID = email.MessageID(evt.ID, domain)
|
meta.MessageID = email.MessageID(evt.ID, domain)
|
||||||
meta.References = meta.References + " " + meta.MessageID
|
meta.References = meta.References + " " + meta.MessageID
|
||||||
b.log.Debug("send email reply: %+v", meta)
|
b.log.Debug("send email reply: %+v", meta)
|
||||||
eml := email.New(meta.MessageID, meta.InReplyTo, meta.References, meta.Subject, meta.From, meta.To, body, htmlBody, nil)
|
eml := email.New(meta.MessageID, meta.InReplyTo, meta.References, meta.Subject, meta.From, meta.To, meta.RcptTo, meta.CC, body, htmlBody, nil)
|
||||||
data := eml.Compose(b.getBotSettings().DKIMPrivateKey())
|
data := eml.Compose(b.getBotSettings().DKIMPrivateKey())
|
||||||
if data == "" {
|
if data == "" {
|
||||||
b.SendError(ctx, evt.RoomID, "email body is empty")
|
b.SendError(ctx, evt.RoomID, "email body is empty")
|
||||||
@@ -208,11 +203,45 @@ type parentEmail struct {
|
|||||||
ThreadID id.EventID
|
ThreadID id.EventID
|
||||||
From string
|
From string
|
||||||
To string
|
To string
|
||||||
|
RcptTo string
|
||||||
|
CC string
|
||||||
InReplyTo string
|
InReplyTo string
|
||||||
References string
|
References string
|
||||||
Subject string
|
Subject string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fixtofrom attempts to "fix" or rather reverse the To, From and CC headers
|
||||||
|
// of parent email by using parent email as metadata source for a new email
|
||||||
|
// that will be sent from postmoogle.
|
||||||
|
// To do so, we need to reverse From and To headers, but Cc should be adjusted as well,
|
||||||
|
// thus that hacky workaround below:
|
||||||
|
func (e *parentEmail) fixtofrom(newSenderMailbox string, preferredDomain string, domains []string) {
|
||||||
|
newSenders := make(map[string]struct{}, len(domains))
|
||||||
|
newSenderPref := newSenderMailbox + "@" + preferredDomain
|
||||||
|
for _, domain := range domains {
|
||||||
|
sender := newSenderMailbox + "@" + domain
|
||||||
|
newSenders[sender] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
originalFrom := e.From
|
||||||
|
// reverse From if needed
|
||||||
|
_, ok := newSenders[e.From]
|
||||||
|
if !ok {
|
||||||
|
e.From = newSenderPref
|
||||||
|
}
|
||||||
|
// reverse To if needed
|
||||||
|
_, ok = newSenders[e.To]
|
||||||
|
if ok {
|
||||||
|
e.To = originalFrom
|
||||||
|
}
|
||||||
|
// replace previous recipient of the email which is sender now with the original From
|
||||||
|
for newSender := range newSenders {
|
||||||
|
if strings.Contains(e.CC, newSender) {
|
||||||
|
e.CC = strings.ReplaceAll(e.CC, newSender, originalFrom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Bot) getParentEvent(evt *event.Event) (id.EventID, *event.Event) {
|
func (b *Bot) getParentEvent(evt *event.Event) (id.EventID, *event.Event) {
|
||||||
content := evt.Content.AsMessage()
|
content := evt.Content.AsMessage()
|
||||||
threadID := utils.EventParent(evt.ID, content)
|
threadID := utils.EventParent(evt.ID, content)
|
||||||
@@ -249,8 +278,8 @@ func (b *Bot) getParentEvent(evt *event.Event) (id.EventID, *event.Event) {
|
|||||||
return threadID, decrypted
|
return threadID, decrypted
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bot) getParentEmail(evt *event.Event, domain string) parentEmail {
|
func (b *Bot) getParentEmail(evt *event.Event, domain string) *parentEmail {
|
||||||
var parent parentEmail
|
parent := &parentEmail{}
|
||||||
threadID, parentEvt := b.getParentEvent(evt)
|
threadID, parentEvt := b.getParentEvent(evt)
|
||||||
parent.ThreadID = threadID
|
parent.ThreadID = threadID
|
||||||
if parentEvt == nil {
|
if parentEvt == nil {
|
||||||
@@ -263,6 +292,8 @@ func (b *Bot) getParentEmail(evt *event.Event, domain string) parentEmail {
|
|||||||
parent.MessageID = email.MessageID(parentEvt.ID, domain)
|
parent.MessageID = email.MessageID(parentEvt.ID, domain)
|
||||||
parent.From = utils.EventField[string](&parentEvt.Content, eventFromKey)
|
parent.From = utils.EventField[string](&parentEvt.Content, eventFromKey)
|
||||||
parent.To = utils.EventField[string](&parentEvt.Content, eventToKey)
|
parent.To = utils.EventField[string](&parentEvt.Content, eventToKey)
|
||||||
|
parent.CC = utils.EventField[string](&parentEvt.Content, eventCcKey)
|
||||||
|
parent.RcptTo = utils.EventField[string](&parentEvt.Content, eventRcptToKey)
|
||||||
parent.InReplyTo = utils.EventField[string](&parentEvt.Content, eventMessageIDkey)
|
parent.InReplyTo = utils.EventField[string](&parentEvt.Content, eventMessageIDkey)
|
||||||
parent.References = utils.EventField[string](&parentEvt.Content, eventReferencesKey)
|
parent.References = utils.EventField[string](&parentEvt.Content, eventReferencesKey)
|
||||||
if parent.InReplyTo == "" {
|
if parent.InReplyTo == "" {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ type Email struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New constructs Email object
|
// New constructs Email object
|
||||||
func New(messageID, inReplyTo, references, subject, from, to, text, html string, files []*utils.File) *Email {
|
func New(messageID, inReplyTo, references, subject, from, to, rcptto, cc, text, html string, files []*utils.File) *Email {
|
||||||
email := &Email{
|
email := &Email{
|
||||||
Date: dateNow(),
|
Date: dateNow(),
|
||||||
MessageID: messageID,
|
MessageID: messageID,
|
||||||
@@ -40,7 +40,8 @@ func New(messageID, inReplyTo, references, subject, from, to, text, html string,
|
|||||||
References: references,
|
References: references,
|
||||||
From: from,
|
From: from,
|
||||||
To: to,
|
To: to,
|
||||||
RcptTo: to,
|
CC: cc,
|
||||||
|
RcptTo: rcptto,
|
||||||
Subject: subject,
|
Subject: subject,
|
||||||
Text: text,
|
Text: text,
|
||||||
HTML: html,
|
HTML: html,
|
||||||
|
|||||||
Reference in New Issue
Block a user