send emails
This commit is contained in:
166
bot/email.go
166
bot/email.go
@@ -3,7 +3,9 @@ package bot
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/format"
|
||||
@@ -12,13 +14,18 @@ import (
|
||||
"gitlab.com/etke.cc/postmoogle/utils"
|
||||
)
|
||||
|
||||
// account data key
|
||||
const acMessagePrefix = "cc.etke.postmoogle.message"
|
||||
// account data keys
|
||||
const (
|
||||
acMessagePrefix = "cc.etke.postmoogle.message"
|
||||
acLastEventPrefix = "cc.etke.postmoogle.last"
|
||||
)
|
||||
|
||||
// event keys
|
||||
const (
|
||||
eventMessageIDkey = "cc.etke.postmoogle.messageID"
|
||||
eventInReplyToKey = "cc.etke.postmoogle.inReplyTo"
|
||||
eventSubjectKey = "cc.etke.postmoogle.subject"
|
||||
eventFromKey = "cc.etke.postmoogle.from"
|
||||
)
|
||||
|
||||
func email2content(email *utils.Email, cfg roomSettings, threadID id.EventID) *event.Content {
|
||||
@@ -46,12 +53,19 @@ func email2content(email *utils.Email, cfg roomSettings, threadID id.EventID) *e
|
||||
Raw: map[string]interface{}{
|
||||
eventMessageIDkey: email.MessageID,
|
||||
eventInReplyToKey: email.InReplyTo,
|
||||
eventSubjectKey: email.Subject,
|
||||
eventFromKey: email.From,
|
||||
},
|
||||
Parsed: parsed,
|
||||
}
|
||||
return &content
|
||||
}
|
||||
|
||||
// SetSMTPAuth sets dynamic login and password to auth against built-in smtp server
|
||||
func (b *Bot) SetMTA(mta utils.MTA) {
|
||||
b.mta = mta
|
||||
}
|
||||
|
||||
// GetMapping returns mapping of mailbox = room
|
||||
func (b *Bot) GetMapping(mailbox string) (id.RoomID, bool) {
|
||||
v, ok := b.rooms.Load(mailbox)
|
||||
@@ -67,7 +81,7 @@ func (b *Bot) GetMapping(mailbox string) (id.RoomID, bool) {
|
||||
}
|
||||
|
||||
// Send email to matrix room
|
||||
func (b *Bot) Send(ctx context.Context, email *utils.Email) error {
|
||||
func (b *Bot) Send2Matrix(ctx context.Context, email *utils.Email) error {
|
||||
roomID, ok := b.GetMapping(utils.Mailbox(email.To))
|
||||
if !ok {
|
||||
return errors.New("room not found")
|
||||
@@ -98,6 +112,7 @@ func (b *Bot) Send(ctx context.Context, email *utils.Email) error {
|
||||
b.setThreadID(roomID, email.MessageID, eventID)
|
||||
threadID = eventID
|
||||
}
|
||||
b.setLastEventID(roomID, threadID, eventID)
|
||||
|
||||
if !cfg.NoFiles() {
|
||||
b.sendFiles(ctx, roomID, email.Files, cfg.NoThreads(), threadID)
|
||||
@@ -105,6 +120,123 @@ func (b *Bot) Send(ctx context.Context, email *utils.Email) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bot) getBody(content *event.MessageEventContent) string {
|
||||
if content.FormattedBody != "" {
|
||||
return content.FormattedBody
|
||||
}
|
||||
|
||||
return content.Body
|
||||
}
|
||||
|
||||
func (b *Bot) getSubject(content *event.MessageEventContent) string {
|
||||
if content.Body == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.SplitN(content.Body, "\n", 1)[0]
|
||||
}
|
||||
|
||||
func (b *Bot) getParentEmail(evt *event.Event) (string, string, string) {
|
||||
content := evt.Content.AsMessage()
|
||||
parentID := utils.EventParent(evt.ID, content)
|
||||
if parentID == evt.ID {
|
||||
return "", "", ""
|
||||
}
|
||||
parentID = b.getLastEventID(evt.RoomID, parentID)
|
||||
parentEvt, err := b.lp.GetClient().GetEvent(evt.RoomID, parentID)
|
||||
if err != nil {
|
||||
b.log.Error("cannot get parent event: %v", err)
|
||||
return "", "", ""
|
||||
}
|
||||
if parentEvt.Content.Parsed == nil {
|
||||
perr := parentEvt.Content.ParseRaw(event.EventMessage)
|
||||
if perr != nil {
|
||||
b.log.Error("cannot parse event content: %v", perr)
|
||||
return "", "", ""
|
||||
}
|
||||
}
|
||||
|
||||
to := utils.EventField[string](&parentEvt.Content, eventFromKey)
|
||||
inReplyTo := utils.EventField[string](&parentEvt.Content, eventMessageIDkey)
|
||||
if inReplyTo == "" {
|
||||
inReplyTo = parentID.String()
|
||||
}
|
||||
|
||||
subject := utils.EventField[string](&parentEvt.Content, eventSubjectKey)
|
||||
if subject != "" {
|
||||
subject = "Re: " + subject
|
||||
} else {
|
||||
subject = strings.SplitN(content.Body, "\n", 1)[0]
|
||||
}
|
||||
|
||||
return to, inReplyTo, subject
|
||||
}
|
||||
|
||||
// Send2Email sends message to email
|
||||
func (b *Bot) Send2Email(ctx context.Context, to, subject, body string) error {
|
||||
var inReplyTo string
|
||||
evt := eventFromContext(ctx)
|
||||
cfg, err := b.getRoomSettings(evt.RoomID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mailbox := cfg.Mailbox()
|
||||
if mailbox == "" {
|
||||
return fmt.Errorf("mailbox not configured, kupo")
|
||||
}
|
||||
from := mailbox + "@" + b.domain
|
||||
pTo, pInReplyTo, pSubject := b.getParentEmail(evt)
|
||||
inReplyTo = pInReplyTo
|
||||
if pTo != "" && to == "" {
|
||||
to = pTo
|
||||
}
|
||||
if pSubject != "" && subject == "" {
|
||||
subject = pSubject
|
||||
}
|
||||
|
||||
content := evt.Content.AsMessage()
|
||||
if subject == "" {
|
||||
subject = b.getSubject(content)
|
||||
}
|
||||
if body == "" {
|
||||
body = b.getBody(content)
|
||||
}
|
||||
|
||||
var msg strings.Builder
|
||||
msg.WriteString("From: ")
|
||||
msg.WriteString(from)
|
||||
msg.WriteString("\r\n")
|
||||
|
||||
msg.WriteString("To: ")
|
||||
msg.WriteString(to)
|
||||
msg.WriteString("\r\n")
|
||||
|
||||
msg.WriteString("Message-Id: ")
|
||||
msg.WriteString(evt.ID.String()[1:] + "@" + b.domain)
|
||||
msg.WriteString("\r\n")
|
||||
|
||||
msg.WriteString("Date: ")
|
||||
msg.WriteString(time.Now().UTC().Format(time.RFC1123Z))
|
||||
msg.WriteString("\r\n")
|
||||
|
||||
if inReplyTo != "" {
|
||||
msg.WriteString("In-Reply-To: ")
|
||||
msg.WriteString(inReplyTo)
|
||||
msg.WriteString("\r\n")
|
||||
}
|
||||
|
||||
msg.WriteString("Subject: ")
|
||||
msg.WriteString(subject)
|
||||
msg.WriteString("\r\n")
|
||||
|
||||
msg.WriteString("\r\n")
|
||||
|
||||
msg.WriteString(body)
|
||||
msg.WriteString("\r\n")
|
||||
|
||||
return b.mta.Send(from, to, msg.String())
|
||||
}
|
||||
|
||||
func (b *Bot) sendFiles(ctx context.Context, roomID id.RoomID, files []*utils.File, noThreads bool, parentID id.EventID) {
|
||||
for _, file := range files {
|
||||
req := file.Convert()
|
||||
@@ -152,3 +284,31 @@ func (b *Bot) setThreadID(roomID id.RoomID, messageID string, eventID id.EventID
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bot) getLastEventID(roomID id.RoomID, threadID id.EventID) id.EventID {
|
||||
key := acLastEventPrefix + "." + threadID.String()
|
||||
data := map[string]id.EventID{}
|
||||
err := b.lp.GetClient().GetRoomAccountData(roomID, key, &data)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "M_NOT_FOUND") {
|
||||
b.log.Error("cannot retrieve account data %s: %v", key, err)
|
||||
return threadID
|
||||
}
|
||||
}
|
||||
|
||||
return data["eventID"]
|
||||
}
|
||||
|
||||
func (b *Bot) setLastEventID(roomID id.RoomID, threadID id.EventID, eventID id.EventID) {
|
||||
key := acLastEventPrefix + "." + threadID.String()
|
||||
data := map[string]id.EventID{
|
||||
"eventID": eventID,
|
||||
}
|
||||
|
||||
err := b.lp.GetClient().SetRoomAccountData(roomID, key, data)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "M_NOT_FOUND") {
|
||||
b.log.Error("cannot save account data %s: %v", key, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user