Home > Enterprise >  Golang IMAP: Move mails in two different folders results in "The specified message set is inval
Golang IMAP: Move mails in two different folders results in "The specified message set is inval

Time:06-04

Use case: we have a mailbox in which we receive mails from customers. Before further processing I have to check if they comply with the agreements (subject has to match a regex, only one attachment per mail, etc.) I have the following application:

import (
    "fmt"
    "imaptest/src/db"
    "io"
    "log"
    "path/filepath"
    "strings"

    "github.com/emersion/go-imap"
    "github.com/emersion/go-imap/client"
    "github.com/emersion/go-message"
    "github.com/iglin/go-config"
)

(...)
//Channel for the messages
messages := make(chan *imap.Message, 10)
//Channel for retrieve if an error appeared
done := make(chan error, 1)
go func() {
  seqset := new(imap.SeqSet)
  seqset.AddRange(1, mbox.Messages)
  //Fetch the messages and push them into the channel
  done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchRFC822}, messages)
}()

//SeqSet for invalid messages
seqsetErrorMessages := new(imap.SeqSet)
//SeqSet for valid messages
seqsetValidMessages := new(imap.SeqSet)

for msg := range messages {
  //Different checks like are there attachments
  //Matches the subject with a specific regex
  if isMessageValid(msg) {
    //Message is valid
    seqsetValidMessages.AddNum(msg.SeqNum)
  } else {
    //Message is invalid
    seqsetErrorMessages.AddNum(msg.SeqNum)
  }
}

//Check if there was an error when fetching the messages
if err := <-done; err != nil {
  log.Fatal(err)
}

//Move all invalid messages to error
if !seqsetErrorMessages.Empty() {
  if err := c.Move(seqsetErrorMessages, FOLDER_ERROR); err != nil {
    log.Fatalf("Error on move to %s: %v", FOLDER_ERROR, err)
  }
}
//Move all valid messages to toExport
if !seqsetValidMessages.Empty() {
  if err := c.Move(seqsetValidMessages, FOLDER_OUT); err != nil {
    log.Fatalf("Error on move to %s: %v", FOLDER_OUT, err)
  }
}

FOLDER_OUT and FOLDER_ERROR are constant strings of existent folders in this mailbox.

In the case that all messages of the source folder are valid (or invalid), everything is fine and all mails are moved.

But if I have the case that there are both valid and invalid mails, I receive the following error:

Error on move to error: The specified message set is invalid.

I also tried to use "msg.Uid" and "c.UidMove()" instead of "msg.Seqnum" and "c.Move()" but this leads to the same result.

How this can be solved?

CodePudding user response:

Using UIDs is the correct answer here, but make sure you have UIDs to start with. "1,4,9" is valid both as a MSN set and as a UID set, but the two aren't interchangeable. You cannot ask for an MSN set from the server and then use it with UID commands.

The problem you see is easily explained if there are precisely two messages in the mailbox and you want to move the first of those to FOLDER_ERROR and the second to FOLDER_OUT. You send a command that says "move the first message in the mailbox to FOLDER_ERROR" and the server does that. Then you send "move the second message in the mailbox to FOLDER_OUT" and the server tells you "there's only one message in this mailbox, there is no second message that I could possibly move".

Using UIDs solves this because those are stable. A message keeps its UID no matter which other messages you move.

  • Related