Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetching and deleting a message over IMAP using cURL

Tags:

bash

curl

imap

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?

like image 754
sonat Avatar asked Dec 23 '22 08:12

sonat


1 Answers

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'
like image 134
larsks Avatar answered Dec 28 '22 06:12

larsks