Fetching and deleting a message over IMAP using cURL
Asked Answered
D

1

5

I want to fetch and delete the top message (with UID=1) through IMAP using curl. I can do it in multiple commands, however when I send the delete command, I have no guarantee that the uid has not changed. Is there a way to persist the imap (or pop3) session in curl?

Deliberation answered 22/3, 2018 at 12:47 Comment(3)
Welcome to StackOverflow! What have you tried? Most of us here are happy to help you improve your craft, but are less happy acting as short order unpaid programming staff. Review how-to-ask, show us your work so far in an MCVE, the result you were expecting and the results you got, and we'll help you figure it out.Vagus
UIDs don't change. MSNs change. 1 is the MSN of the top/bottom/oldest message in a mailbox. Deleting one message doesn't change the UID of another.Reclinate
'1' is not a UID. '1' is just a message number. If you delete message 9, and a new message comes in, that will also be message 9.Nona
N
13

You actually do have a guarantee that the UID has not changed: this is what the IMAP UIDVALIDITY field is all about. As long as the UIDVALIDITY value for a mailbox has not changed, any message UIDs you have will continue to point to the same message. Read about this in more detail in the IMAP RFC.

Using curl, you can assert a UIDVALIDITY value in a request by including that in the IMAP URL, like this:

curl 'imaps://imap.example.com/inbox;UIDVALIDITY=6' ...

If the UIDVALIDITY has changed, curl will report:

curl: (78) Mailbox UIDVALIDITY has changed

You can see the UIDVALIDITY value for a mailbox by passing the -v option to curl when doing, e.g., an EXAMINE:

$ curl -v imaps://imap.example.com/ -X 'examine inbox'
[...]
> A003 examine inbox
< * FLAGS (\Answered \Flagged \Draft \Deleted \Seen $NotPhishing $Phishing Old SEEN)
< * OK [PERMANENTFLAGS ()] Flags permitted.
< * OK [UIDVALIDITY 7] UIDs valid.
< * 9 EXISTS
< * 0 RECENT
< * OK [UIDNEXT 7422] Predicted next UID.
< * OK [HIGHESTMODSEQ 14264365]
< A003 OK [READ-ONLY] inbox selected. (Success)

A necessary prerequisite to using the UIDVALIDITY value is to request message uids. You can ask for the UID attribute when fetching information about messages:

$ curl -sv  --netrc   'imaps://imap.example.com/inbox' -X 'fetch 1:* (UID FLAGS)'
[...]
< * 1 FETCH (UID 7186 FLAGS (\Seen))
< * 2 FETCH (UID 7188 FLAGS (\Seen))
< * 3 FETCH (UID 7278 FLAGS (\Seen))
< * 4 FETCH (UID 7288 FLAGS (Old \Seen))
< * 5 FETCH (UID 7364 FLAGS (\Seen))
< * 6 FETCH (UID 7413 FLAGS (\Seen))
< * 7 FETCH (UID 7417 FLAGS (\Seen))
< * 8 FETCH (UID 7419 FLAGS (\Seen))
< * 9 FETCH (UID 7421 FLAGS (\Seen))

Once you have a UID, you can use that to refer to a message by prefixing commands with the UID keyword. For example, instead of asking for message 9 like this:

FETCH 9 (ENVELOPE)

We would instead need to send the following IMAP command:

UID FETCH 7421 (ENVELOPE)

Curl doesn't appear to have native support for UID commands, but we can pass custom commands using the -X option. For example, to fetch message with UID 7421, we would run:

curl 'imaps://imap.example.com/inbox;uidvalidity=7' -X 'UID FETCH 7421 (ENVELOPE)'

This would assert that the mailbox UIDVALIDITY must still be 7 (because if it has changed, our UID is no longer valid), and retrieve the message envelope.

To delete that message:

curl 'imaps://imap.example.com/inbox;uidvalidity=7' -X 'UID STORE 7421 +Flags \Deleted'
Nona answered 22/3, 2018 at 13:42 Comment(2)
Thank you very much! This is awesome. I wish I could upvote it but I have only 4 pts. Is there a similar method for POP3? As far as I know only some extensions of POP3 has UID support.Deliberation
If this answered your question you can mark the answer as "accepted" by clicking on the checkmark to the left of the answer. I'm not sure about POP3.Nona

© 2022 - 2024 — McMap. All rights reserved.