====== Curl - Perform imap queries using Curl ======
If you have an IMAP or IMAPS server you can "read your email" using Curl. To get started you'll first of all need to know:
* Your mail-server address.
* Your mail login.
* Your mail password.
----
===== 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"
If you leave out the password from the **--user** argument, curl will prompt you for the password before it preforms the request. This way you're not leaking your password to your shell history or the process list.
Curl also supports .netrc lookup of user:password with -n, if the **--user** argument is left off.
returns
..
..
* LIST (\HasNoChildren) "/" xen-users
* LIST (\HasNoChildren) "/" mentors-debian-org
* LIST (\HasNoChildren) "/" fairshare
* LIST (\HasNoChildren) "/" INBOX
Here 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"
returns:
* OK [PERMANENTFLAGS ()] Read-only mailbox.
* 9465 EXISTS
* 3266 RECENT
* OK [UIDVALIDITY 1373146046] UIDs valid
* OK [UIDNEXT 9468] Predicted next UID
This 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"
returns:
..
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"
returns:
Date: Sat, 14 Apr 2012 14:13:41 +0300 (EEST)
From: Steve Kemp
To: Steve Kemp
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)]"
returns:
..
Subject: Re: Fancy a cake?
..
The reason for avoiding custom-requests where possible is that when you're using the curl API programatically 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"
done
This 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
----
===== CurlMail Script =====
#!/bin/bash
# /usr/local/bin/curlmail
# http://crystalfaeries.net/posix/bin/curlmail
# celeste crystalfaery 2016-02-24 22:27:10+00:00
# https://debian-administration.org/article/726/Performing_IMAP_queries_via_curl
# read(only) IMAPS INBOX (using ~/.netrc for password)
# (machine example.org login user password my_password)
# 1st argument is machine name (else talk to self if not specified)
# 2..n argument(s) (optional) are message number(s) to view
# e.g.: curlmail example.org 3 1 4
help=10 # this line number of file -1
# NOTE: remove the "--insecure" argument to curl if server(s) have real certificate vs self-signed certificate
# NOTE: we do not sanitize the server argument, so as-is don't make this into a cgi
function cleanup {
if [ -e /tmp/$$ ]; then
rm /tmp/$$ # cleanup our temporary file
fi
}
trap cleanup INT TERM # cleanup our temporary file
case $# in
0)
exec $0 `hostname` # talk to myself
exit -1 # exec doesn't return, right?
;;
1)
case "$1" in
-v)
tail -n +4 $0 | head -n 1
;;
--version)
tail -n +4 $0 | head -n 1
;;
-h)
head -n $help $0 | tail -n +6
;;
--help)
head -n $help $0 | tail -n +6
;;
*)
let uid=0
while let uid=$uid+1
do # iterate available messages
echo -n "${uid}: " >> /tmp/$$
chmod 600 /tmp/$$
curl -# --insecure -n --url \
"imaps://${1}/INBOX;UID=${uid};SECTION=HEADER.FIELDS%20(DATE%20FROM%20TO%20SUBJECT)" >> /tmp/$$ 2>/dev/null || break
done
sed 's/\n\n/\n/g' < /tmp/$$ | less
rm /tmp/$$
;;
esac
exit
;;
*)
server="$1"
shift
while [ $# != 0 ]
do # iterate requested messages
message=`echo "$1" | tr -d -c '[:digit:]'` # sanitize input
shift
rm /tmp/$$ 2>/dev/null
echo -n "${message}: " >> /tmp/$$
chmod 600 /tmp/$$
curl -# --insecure -n --url "imaps://${server}/INBOX;UID=${message}" >> /tmp/$$ 2>/dev/null
sed 's/\n\n/\n/g' < /tmp/$$ | less
rm /tmp/$$
done
exit
;;
esac
----
===== References =====
http://crystalfaeries.net/fae/curlmail.html