Performing IMAP queries via curl
Most people are familiar with curl, the tool that allows you to make HTTP-requests, and FTP-requests, via the command-line. Recently it gained the ability to perform IMAP operations, and this brief article demonstrates how that is done.
The curl command can be installed, if not already present, via:
aptitude install curl
Once installed you can make simple HTTP-fetches like so:
$ curl https://www.debian-administration.org/ .. .. </div> </body> </html>
This is probably already familiar to you, but if you have an IMAP or IMAPS server you can do more – you can "read your email". To get started you'll first of all need to know:
- Your mail-server address.
- Your mail login.
- Your mail password.
We'll be calling commands via the shell, so bear in mind this is woefully insecure if you're on a shared system – because other users could see your command, and see the password you've submitted. On a single-user system this is perhaps acceptible though.
Listing Folders
The initial example will connect us to the IMAP server at imap.example.com, using username bobby and password tables:
$ curl --url "imap://mail.example.com/" --user "bobby:tables" .. .. * LIST (HasNoChildren) "/" xen-users * LIST (HasNoChildren) "/" mentors-debian-org * LIST (HasNoChildren) "/" fairshare * LIST (HasNoChildren) "/" INBOXHere we see that we've connected, and received a list of folders, including "xen-users", "fairshare", and the "INBOX".
If your mail-server is running over SSL then instead of using imap:// you should set the schema to imaps://, it may be that you're using a self-signed certificate in that case you'd add –insecure to avoid checking the certificate trust-chain.
This would look like so:
$ curl --insecure --url "imaps://mail.example.com/" --user "bobby:tables"
Discovering Messages
With the previous example we looked at listing mailboxes. What if we wanted to actually view a message? To fetch a message we need the identifier of the message to fetch – so we need to find out how many messages exist, as message-IDs are sequential.
To see how many messages exist in the folder "People-Steve" we'd run this:
$ curl --insecure --url "imaps://mail.example.com/" --user "bobby:tables" --request "EXAMINE People-Steve" * OK [PERMANENTFLAGS ()] Read-only mailbox. * 9465 EXISTS * 3266 RECENT * OK [UIDVALIDITY 1373146046] UIDs valid * OK [UIDNEXT 9468] Predicted next UIDThis tells us that there are 9465 messages. So we can probably assume that fetching a message with each of these IDs will work: 1, 2, 3, … 9465, & 9465.
Fetching A Single Message
Fetching a message is simple if you know both the folder from which it comes and the ID of the message you wish to retrieve.
We've already shown that the folder "People-Steve" contains nearly ten-thousand messages, so this next example will show us fetching the message with ID 512:
$ curl --insecure --url "imaps://mail.example.com/People-Steve;UID=512" --user "bobby:tables" .. X-HELO: mail.cs.helsinki.fi X-REMOTE-IP: 128.214.9.1 X-REMOTE-HOST: courier.cs.helsinki.fi .. .. I just accidentally someone! (see facebook) ..Fetching the message includes both the headers and the body. If you want to fetch just the headers, or a subset, things are a little fiddlier due to URL-encoding. This example gets the headers "to", "from", "date", and "subject":
$ curl --insecure --url "imaps://mail.example.com/People-Steve;UID=512;SECTION=HEADER.FIELDS%20(DATE%20FROM%20TO%20SUBJECT)" --user "bobby:tables" Date: Sat, 14 Apr 2012 14:13:41 +0300 (EEST) From: Steve Kemp <[email protected]> To: Steve Kemp <[email protected]> Subject: Re: Fancy a cake?We could have avoided the use of URL-encoding and instead sent a custom-request, like so:
$ curl --insecure --verbose --url "imaps://imap.example.com/People-Steve" --user "bobby:tables" --request "fetch 512 BODY.PEEK[HEADER.FIELDS (Subject)]" .. Subject: Re: Fancy a cake? ..The reason for avoiding custom-requests where possible is that when you're using the curl API programattically you'll discover that responses are not decoded – which is a known issue.
In the example above we'd have received zero output unless/until we added the –verbose flag. Precisely because curl has received the output from the IMAP-server but not decoded it and presented it to us.
Simple Shell Scripts
As a quick hack the following shell-script will dump the subject of the first ten messages in the given mailbox:
#!/bin/sh # Dump the subject of the first ten messages in the folder. for id in `seq 1 10` ; do echo "Message ${id}" curl --insecure --url "imaps://mail.example.com/People-Steve;UID=${id};SECTION=HEADER.FIELDS%20(SUBJECT)" --user "bobby:tables" doneThis takes no account of the maximum message-ID. You could just keep going indefinitely, to dump all subjects and stop on error:
#!/bin/sh # Dump the subject of all messages in the folder. id=1 while true ; do echo "Message ${id}" curl --insecure --url "imaps://mail.example.com/People-Steve;UID=${id};SECTION=HEADER.FIELDS%20(SUBJECT)" --user "bobby:tables" || exit id=`expr $id + 1` done