when delivering a message to a mailbox, lazily parse the parsed form of the message

it isn't always needed, so this can improve performance a bit.
come up as part of other refactoring.
This commit is contained in:
Mechiel Lukkien 2025-03-01 09:54:37 +01:00
parent 3050baa15a
commit 1037a756fa
No known key found for this signature in database

View File

@ -1695,9 +1695,9 @@ func (a *Account) DeliverMessage(log mlog.Log, tx *bstore.Tx, m *Message, msgFil
conf, _ := a.Conf() conf, _ := a.Conf()
m.JunkFlagsForMailbox(mb, conf) m.JunkFlagsForMailbox(mb, conf)
mr := FileMsgReader(m.MsgPrefix, msgFile) // We don't close, it would close the msgFile.
var part *message.Part var part *message.Part
if m.ParsedBuf == nil { if m.ParsedBuf == nil {
mr := FileMsgReader(m.MsgPrefix, msgFile) // We don't close, it would close the msgFile.
p, err := message.EnsurePart(log.Logger, false, mr, m.Size) p, err := message.EnsurePart(log.Logger, false, mr, m.Size)
if err != nil { if err != nil {
log.Infox("parsing delivered message", err, slog.String("parse", ""), slog.Int64("message", m.ID)) log.Infox("parsing delivered message", err, slog.String("parse", ""), slog.Int64("message", m.ID))
@ -1709,13 +1709,24 @@ func (a *Account) DeliverMessage(log mlog.Log, tx *bstore.Tx, m *Message, msgFil
return fmt.Errorf("marshal parsed message: %w", err) return fmt.Errorf("marshal parsed message: %w", err)
} }
m.ParsedBuf = buf m.ParsedBuf = buf
} else { }
var partTried bool
getPart := func() *message.Part {
if part != nil {
return part
}
if partTried {
return nil
}
partTried = true
var p message.Part var p message.Part
if err := json.Unmarshal(m.ParsedBuf, &p); err != nil { if err := json.Unmarshal(m.ParsedBuf, &p); err != nil {
log.Errorx("unmarshal parsed message, continuing", err, slog.String("parse", "")) log.Errorx("unmarshal parsed message, continuing", err, slog.String("parse", ""))
} else { } else {
part = &p part = &p
} }
return part
} }
// If we are delivering to the originally intended mailbox, no need to store the mailbox ID again. // If we are delivering to the originally intended mailbox, no need to store the mailbox ID again.
@ -1723,13 +1734,13 @@ func (a *Account) DeliverMessage(log mlog.Log, tx *bstore.Tx, m *Message, msgFil
m.MailboxDestinedID = 0 m.MailboxDestinedID = 0
} }
if part != nil && m.MessageID == "" && m.SubjectBase == "" { if m.MessageID == "" && m.SubjectBase == "" && getPart() != nil {
m.PrepareThreading(log, part) m.PrepareThreading(log, part)
} }
// Assign to thread (if upgrade has completed). // Assign to thread (if upgrade has completed).
noThreadID := nothreads noThreadID := nothreads
if m.ThreadID == 0 && !nothreads && part != nil { if m.ThreadID == 0 && !nothreads && getPart() != nil {
select { select {
case <-a.threadsCompleted: case <-a.threadsCompleted:
if a.threadsErr != nil { if a.threadsErr != nil {
@ -1760,7 +1771,7 @@ func (a *Account) DeliverMessage(log mlog.Log, tx *bstore.Tx, m *Message, msgFil
} }
// todo: perhaps we should match the recipients based on smtp submission and a matching message-id? we now miss the addresses in bcc's if the mail client doesn't save a message that includes the bcc header in the sent mailbox. // todo: perhaps we should match the recipients based on smtp submission and a matching message-id? we now miss the addresses in bcc's if the mail client doesn't save a message that includes the bcc header in the sent mailbox.
if mb.Sent && part != nil && part.Envelope != nil { if mb.Sent && getPart() != nil && part.Envelope != nil {
e := part.Envelope e := part.Envelope
sent := e.Date sent := e.Date
if sent.IsZero() { if sent.IsZero() {