mail queue

This commit is contained in:
Aine
2022-11-14 20:02:13 +02:00
parent ce1599d8a3
commit eb07bc1ac7
10 changed files with 302 additions and 74 deletions

View File

@@ -15,6 +15,7 @@ import (
// account data keys
const (
acQueueKey = "cc.etke.postmoogle.mailqueue"
acMessagePrefix = "cc.etke.postmoogle.message"
acLastEventPrefix = "cc.etke.postmoogle.last"
)
@@ -34,6 +35,21 @@ func (b *Bot) SetSendmail(sendmail func(string, string, string) error) {
b.sendmail = sendmail
}
// Sendmail tries to send email immediately, but if it gets 4xx error (greylisting),
// the email will be added to the queue and retried several times after that
func (b *Bot) Sendmail(eventID id.EventID, from, to, data string) error {
err := b.sendmail(from, to, data)
if err != nil {
if strings.HasPrefix(err.Error(), "45") {
b.log.Debug("email %s (from=%s to=%s) was added to the queue: %v", eventID, from, to, err)
return b.enqueueEmail(eventID.String(), from, to, data)
}
return err
}
return nil
}
// GetDKIMprivkey returns DKIM private key
func (b *Bot) GetDKIMprivkey() string {
return b.getBotSettings().DKIMPrivateKey()
@@ -89,8 +105,8 @@ func (b *Bot) IncomingEmail(ctx context.Context, email *utils.Email) error {
b.Error(ctx, roomID, "cannot get settings: %v", err)
}
b.lock(roomID)
defer b.unlock(roomID)
b.lock(roomID.String())
defer b.unlock(roomID.String())
var threadID id.EventID
if email.InReplyTo != "" || email.References != "" {
@@ -119,6 +135,56 @@ func (b *Bot) IncomingEmail(ctx context.Context, email *utils.Email) error {
return nil
}
// SendEmailReply sends replies from matrix thread to email thread
func (b *Bot) SendEmailReply(ctx context.Context) {
evt := eventFromContext(ctx)
cfg, err := b.getRoomSettings(evt.RoomID)
if err != nil {
b.Error(ctx, evt.RoomID, "cannot retrieve room settings: %v", err)
return
}
mailbox := cfg.Mailbox()
if mailbox == "" {
b.Error(ctx, evt.RoomID, "mailbox is not configured, kupo")
return
}
b.lock(evt.RoomID.String())
defer b.unlock(evt.RoomID.String())
fromMailbox := mailbox + "@" + b.domains[0]
meta := b.getParentEmail(evt)
// when email was sent from matrix and reply was sent from matrix again
if fromMailbox != meta.From {
meta.To = meta.From
}
if meta.To == "" {
b.Error(ctx, evt.RoomID, "cannot find parent email and continue the thread. Please, start a new email thread")
return
}
meta.ThreadID = b.getThreadID(evt.RoomID, meta.InReplyTo, meta.References)
content := evt.Content.AsMessage()
if meta.Subject == "" {
meta.Subject = strings.SplitN(content.Body, "\n", 1)[0]
}
body := content.Body
ID := utils.MessageID(evt.ID, b.domains[0])
meta.References = meta.References + " " + ID
b.log.Debug("send email reply ID=%s meta=%+v", ID, meta)
email := utils.NewEmail(ID, meta.InReplyTo, meta.References, meta.Subject, fromMailbox, meta.To, body, "", nil)
data := email.Compose(b.getBotSettings().DKIMPrivateKey())
err = b.Sendmail(evt.ID, meta.From, meta.To, data)
if err != nil {
b.Error(ctx, evt.RoomID, "cannot send email: %v", err)
return
}
b.saveSentMetadata(ctx, meta.ThreadID, email, &cfg)
}
type parentEmail struct {
MessageID string
ThreadID id.EventID
@@ -196,56 +262,6 @@ func (b *Bot) getParentEmail(evt *event.Event) parentEmail {
return parent
}
// SendEmailReply sends replies from matrix thread to email thread
func (b *Bot) SendEmailReply(ctx context.Context) {
evt := eventFromContext(ctx)
cfg, err := b.getRoomSettings(evt.RoomID)
if err != nil {
b.Error(ctx, evt.RoomID, "cannot retrieve room settings: %v", err)
return
}
mailbox := cfg.Mailbox()
if mailbox == "" {
b.Error(ctx, evt.RoomID, "mailbox is not configured, kupo")
return
}
b.lock(evt.RoomID)
defer b.unlock(evt.RoomID)
fromMailbox := mailbox + "@" + b.domains[0]
meta := b.getParentEmail(evt)
// when email was sent from matrix and reply was sent from matrix again
if fromMailbox != meta.From {
meta.To = meta.From
}
if meta.To == "" {
b.Error(ctx, evt.RoomID, "cannot find parent email and continue the thread. Please, start a new email thread")
return
}
meta.ThreadID = b.getThreadID(evt.RoomID, meta.InReplyTo, meta.References)
content := evt.Content.AsMessage()
if meta.Subject == "" {
meta.Subject = strings.SplitN(content.Body, "\n", 1)[0]
}
body := content.Body
ID := utils.MessageID(evt.ID, b.domains[0])
meta.References = meta.References + " " + ID
b.log.Debug("send email reply ID=%s meta=%+v", ID, meta)
email := utils.NewEmail(ID, meta.InReplyTo, meta.References, meta.Subject, fromMailbox, meta.To, body, "", nil)
data := email.Compose(b.getBotSettings().DKIMPrivateKey())
err = b.sendmail(meta.From, meta.To, data)
if err != nil {
b.Error(ctx, evt.RoomID, "cannot send email: %v", err)
return
}
b.saveSentMetadata(ctx, meta.ThreadID, email, &cfg)
}
// saveSentMetadata used to save metadata from !pm sent and thread reply events to a separate notice message
// because that metadata is needed to determine email thread relations
func (b *Bot) saveSentMetadata(ctx context.Context, threadID id.EventID, email *utils.Email, cfg *roomSettings) {