diff --git a/Changelog.md b/Changelog.md index 0d3e669b..3fdbddda 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) ### Fixed * GODT-798 Replace, don't add, transfer encoding when making body 7-bit clean. +* Move/Copy duplicate for emails with References in Outlook ## [Bridge 1.4.3] Forth diff --git a/internal/imap/mailbox_message.go b/internal/imap/mailbox_message.go index 5d25a2ae..5ae84d9c 100644 --- a/internal/imap/mailbox_message.go +++ b/internal/imap/mailbox_message.go @@ -24,7 +24,6 @@ import ( "mime/multipart" "net/mail" "net/textproto" - "regexp" "sort" "strings" "time" @@ -141,18 +140,19 @@ func (im *imapMailbox) CreateMessage(flags []string, date time.Time, body imap.L references := m.Header.Get("References") referenceList := strings.Fields(references) - if len(referenceList) > 0 { + // In case there is a mail client which corrupts headers, try + // "References" too. + if internalID == "" && len(referenceList) > 0 { lastReference := referenceList[len(referenceList)-1] - // In case we are using a mail client which corrupts headers, try "References" too. - re := regexp.MustCompile(pmapi.InternalReferenceFormat) - match := re.FindStringSubmatch(lastReference) - if len(match) > 0 { - internalID = match[0] + match := pmapi.RxInternalReferenceFormat.FindStringSubmatch(lastReference) + if len(match) == 2 { + internalID = match[1] } } - // Avoid appending a message which is already on the server. Apply the new - // label instead. This sometimes happens which Outlook (it uses APPEND instead of COPY). + // Avoid appending a message which is already on the server. Apply the + // new label instead. This always happens with Outlook (it uses APPEND + // instead of COPY). if internalID != "" { // Check to see if this belongs to a different address in split mode or another ProtonMail account. msg, err := im.storeMailbox.GetMessage(internalID) diff --git a/internal/smtp/user.go b/internal/smtp/user.go index 079c920f..37957249 100644 --- a/internal/smtp/user.go +++ b/internal/smtp/user.go @@ -25,7 +25,6 @@ import ( "io" "mime" "net/mail" - "regexp" "strings" "time" @@ -408,9 +407,9 @@ func (su *smtpUser) handleReferencesHeader(m *pmapi.Message) (draftID, parentID if !strings.Contains(reference, "@"+pmapi.InternalIDDomain) { newReferences = append(newReferences, reference) } else { // internalid is the parentID. - idMatch := regexp.MustCompile(pmapi.InternalReferenceFormat).FindStringSubmatch(reference) - if len(idMatch) > 0 { - lastID := strings.TrimSuffix(strings.Trim(idMatch[0], "<>"), "@protonmail.internalid") + idMatch := pmapi.RxInternalReferenceFormat.FindStringSubmatch(reference) + if len(idMatch) == 2 { + lastID := idMatch[1] filter := &pmapi.MessagesFilter{ID: []string{lastID}} if su.addressID != "" { filter.AddressID = su.addressID diff --git a/pkg/pmapi/messages.go b/pkg/pmapi/messages.go index ed5d38b5..623bd07b 100644 --- a/pkg/pmapi/messages.go +++ b/pkg/pmapi/messages.go @@ -29,6 +29,7 @@ import ( "net/http" "net/mail" "net/url" + "regexp" "strconv" "strings" @@ -149,8 +150,9 @@ const ConversationIDDomain = `protonmail.conversationid` // InternalIDDomain is used as a placeholder for reference/message ID headers to improve compatibility with various clients. const InternalIDDomain = `protonmail.internalid` -// InternalReferenceFormat describes format of the message ID (as regex) used for parsing reference headers. -const InternalReferenceFormat = `(?U)<.*@` + InternalIDDomain + `>` +// RxInternalReferenceFormat is compiled regexp which describes the match for +// a message ID used in reference headers. +var RxInternalReferenceFormat = regexp.MustCompile(`(?U)<(.+)@` + regexp.QuoteMeta(InternalIDDomain) + `>`) //nolint[gochecknoglobals] // Message structure. type Message struct {