
An IMAP Client for R
mRpostman is a session-based IMAP client that implements
the full command sets of the IMAP4rev2 (RFC 9051) and IMAP4rev1 (RFC
3501) protocols, along with the optional extensions registered with the
Internet Assigned Numbers Authority (IANA), allowing you to perform
virtually all e-mail operations from within R. The aim of this package
is to pave the way for email data analysis in R. To do so,
mRpostman makes extensive use of the {curl} package and the
libcurl C library. Since version 3.0.0, searches are written as plain R
expressions through query(), and every method returns a
value ready for the analysis stage.
mRpostman’s official website: https://allanvc.github.io/mRpostman/
Cite mRpostman: A. V. C. Quadros, “mRpostman: An IMAP
Client for R”, Journal of Open Research Software, vol. 12, no. 1, p. 4,
2024, doi: 10.5334/jors.480. http. Refer to
citation("mRpostman").
Version 3.0.0 is the product of a deep refactoring of the package, and a few changes are not backward compatible:
use_uid now defaults to
TRUE: every method operates on message UIDs
instead of sequence numbers by default. UIDs are stable identifiers
(sequence numbers are renumbered whenever messages are expunged), so ids
remain valid across sessions — but scripts that relied on sequence
numbers under the old default must now pass use_uid = FALSE
(once, at configure_imap(), if preferred).search_*() methods and the
AND()/OR() helpers are
soft-deprecated: searches are now written as plain R
expressions through query(), or with the criteria
constructors combined by the native &, |,
and ! operators.fetch_attachments(),
fetch_attachments_list(), get_attachments(),
list_attachments()) are also
soft-deprecated, replaced by
attachments(), attachments_manifest(), and
extract_attachments().name, to_folder, and
msg_uid arguments were unified as folder and
msg_id throughout the API; the old names still work but
warn once per session.use_uid, mute, and retries
can now be set once, in configure_imap(), as
connection-level defaults.Nothing was removed: the deprecated spellings keep working and emit lifecycle warnings pointing to their replacements. See NEWS.md for the complete list of changes.
| Provider | IMAP Server |
|---|---|
| Gmail | imap.gmail.com |
| Office 365 | outlook.office365.com* |
| Outlook.com (Hotmail and Live.com) | imap-mail.outlook.com |
| Yahoo Mail | imap.mail.yahoo.com |
| iCloud Mail | imap.mail.me.com |
| AOL Mail | imap.aol.com |
| Zoho Mail | imap.zoho.com |
| Yandex Mail | imap.yandex.com |
| GMX Mail | imap.gmx.com |
| Mail.com | imap.mail.com |
| FastMail | imap.fastmail.com |
* For Office 365 accounts, the username should be set as
user@yourcompany.com or
user@youruniversity.edu for example.
From version 0.9.0.0 onward, mRpostman is implemented
under the OO paradigm, based on an R6 class called ImapCon.
Its derived methods, and a few independent functions enable the R user
to perform a myriad of IMAP commands.
The main groups, in the shape the package has since 3.0.0:
configure_imap()
(including the connection-level defaults use_uid,
mute, and retries), disconnect(),
the reset_*() setters;query(), an ordinary R
expression such as
con$query((subject == "budget" | "budget 3") & flag != "SEEN");
search() with the criteria constructors
(string(), before(), flag(),
verbatim(), …) combined by the native &,
|, and !; the older search_*()
methods and AND()/OR() keep working as
deprecated spellings;fetch_body(),
fetch_header(), fetch_text(),
fetch_metadata(), fetch_envelope(),
fetch_bodystructure(), and the decoders
clean_msg_text() and
decode_mime_header();attachments_manifest()
(list without downloading), attachments() (download, guided
by the BODYSTRUCTURE), and
extract_attachments() for already-fetched messages;append_msg()/append_msgs(), expunge;sort(), thread(), the esearch_*()
aggregates, idle() and notify() on a dedicated
raw-socket route, plus every capability extension registered with IANA
(quota, ACL, metadata, CONDSTORE/QRESYNC, and the rest).The IMAP protocol has a mandatory core — the
IMAP4rev1 commands defined in RFC 3501,
revised and consolidated by IMAP4rev2 in RFC 9051, which
every compliant server must implement — plus a set of optional
extensions, each advertised by the server in its
CAPABILITY response. mRpostman covers both.
For the extension-based methods, mRpostman checks the
server’s advertised capabilities and, if the required one is missing,
raises an informative error instead of letting the server reply with a
cryptic BAD Unknown command. You can inspect what your
server supports with list_server_capabilities().
| IMAP command | mRpostman method(s) |
|---|---|
CAPABILITY |
list_server_capabilities() |
NOOP |
noop() |
CHECK |
check() |
LOGIN / AUTHENTICATE |
configure_imap() |
LOGOUT |
disconnect() |
SELECT / EXAMINE |
select_folder() / examine_folder() |
CREATE / DELETE / RENAME |
create_folder() / delete_folder() /
rename_folder() |
SUBSCRIBE / UNSUBSCRIBE |
subscribe_folder() /
unsubscribe_folder() |
LIST / LSUB |
list_mail_folders() /
list_subscribed_folders() |
STATUS |
status() |
APPEND |
append_msg() |
SEARCH |
search(), search_before(),
search_since(), search_string(), … (all
search_*) |
FETCH |
fetch_body(), fetch_header(),
fetch_text(), fetch_metadata(),
fetch_attachments() |
STORE |
add_flags(), remove_flags(),
replace_flags() |
COPY |
copy_msg() |
CLOSE |
close_folder() |
EXPUNGE |
expunge(), delete_msg() |
| IMAP command | mRpostman method(s) |
Capability | RFC |
|---|---|---|---|
SORT |
sort() |
SORT |
5256 |
THREAD |
thread() |
THREAD=REFERENCES / THREAD=ORDEREDSUBJECT
/ THREAD=REFS |
5256 |
GETQUOTA / GETQUOTAROOT |
get_quota() / get_quota_root() |
QUOTA |
9208 |
NAMESPACE |
namespace() |
NAMESPACE |
2342 |
ID |
id() |
ID |
2971 |
UNSELECT |
unselect_folder() |
UNSELECT |
3691 |
LIST (special-use) |
list_special_use_folders() |
SPECIAL-USE |
6154 |
MOVE |
move_msg() |
MOVE |
6851 |
SEARCH RETURN (ESEARCH) |
search(esearch = TRUE), esearch_count(),
esearch_min_id(), esearch_max_id() |
ESEARCH |
4731 |
UID EXPUNGE, APPENDUID /
COPYUID |
expunge(msg_uid = ...), append_msg()
(returns the UID), copy_msg() / move_msg()
("copyuid" attribute) |
UIDPLUS |
4315 |
LIST ... RETURN (STATUS ...) |
list_folders_status() |
LIST-STATUS |
5819 |
SETQUOTA |
set_quota() |
QUOTA |
9208 |
GETACL / SETACL / DELETEACL /
LISTRIGHTS / MYRIGHTS |
get_acl() / set_acl() /
delete_acl() / list_rights() /
my_rights() |
ACL |
4314 |
ENABLE |
enable() |
ENABLE |
5161 |
SEARCH RETURN (SAVE) |
search(save = TRUE), then msg_id = "$" in
fetch/flag/copy/move/delete methods |
SEARCHRES |
5182 |
SORT RETURN (...) |
sort(return = ...) |
ESORT |
5267 |
LIST ... RETURN (CHILDREN SUBSCRIBED SPECIAL-USE) |
list_mail_folders(detailed = TRUE) |
LIST-EXTENDED |
5258 |
STATUS (SIZE) |
status(items = "SIZE"),
list_folders_status(items = "SIZE") |
STATUS=SIZE |
8438 |
FETCH (PREVIEW) |
fetch_preview(),
fetch_metadata(attribute = "PREVIEW") |
PREVIEW |
8970 |
FETCH (SAVEDATE),
SEARCH SAVEDBEFORE/SAVEDON/SAVEDSINCE |
fetch_metadata(attribute = "SAVEDATE"),
saved_before() / saved_on() /
saved_since() |
SAVEDATE |
8514 |
SELECT (CONDSTORE),
STATUS (HIGHESTMODSEQ), FETCH (MODSEQ),
FETCH ... (CHANGEDSINCE),
STORE ... (UNCHANGEDSINCE), SEARCH MODSEQ |
select_folder(condstore = TRUE),
status(items = "HIGHESTMODSEQ"),
fetch_metadata(attribute = "MODSEQ", changed_since = ),
add_flags()/replace_flags()/remove_flags()
(unchanged_since = ), modseq() |
CONDSTORE |
7162 |
SELECT (QRESYNC ...),
UID FETCH ... (CHANGEDSINCE VANISHED) |
resync_folder(), fetch_changes() |
QRESYNC |
7162 |
GETMETADATA / SETMETADATA |
get_metadata() / set_metadata() |
METADATA |
5464 |
IDLE |
idle() (on a dedicated second connection) |
IDLE |
2177 |
APPEND (multiple literals) |
append_msgs() |
MULTIAPPEND |
3502 |
NOTIFY SET / NOTIFY NONE |
notify() |
NOTIFY |
5465 |
FETCH (BINARY.PEEK[...]) |
fetch_binary() |
BINARY |
3516 |
APPEND ... CATENATE |
append_catenate(), imap_url() |
CATENATE |
4469 |
COMPRESS DEFLATE |
compress = TRUE in the raw-socket methods |
COMPRESS=DEFLATE |
4978 |
LIST ... RETURN (MYRIGHTS) |
list_mail_folders(detailed = TRUE)
(my_rights column) |
LIST-MYRIGHTS |
8440 |
CREATE ... (USE (...)) |
create_folder(special_use = ...) |
CREATE-SPECIAL-USE |
6154 |
AUTHENTICATE OAUTHBEARER |
configure_imap(oauth_mechanism = "OAUTHBEARER") |
AUTH=OAUTHBEARER |
7628 |
SORT (display keys) |
sort(by = "DISPLAYFROM"/"DISPLAYTO") |
SORT=DISPLAY |
5957 |
SEARCH RETURN (PARTIAL m:n) |
esearch_partial() |
PARTIAL / CONTEXT=SEARCH |
9394 / 5267 |
SORT RETURN (PARTIAL m:n) |
esort_partial() * |
CONTEXT=SORT |
5267 |
REPLACE |
replace_msg() * |
REPLACE |
8508 |
FETCH (EMAILID THREADID),
STATUS (MAILBOXID) |
fetch_objectid() *,
status(items = "MAILBOXID") * |
OBJECTID |
8474 |
UIDBATCHES |
uid_batches() * |
UIDBATCHES |
10022 |
ESEARCH IN (...) |
esearch_multi() * |
MULTISEARCH |
7377 |
UNAUTHENTICATE |
unauthenticate() * |
UNAUTHENTICATE |
8437 |
LANGUAGE / COMPARATOR |
language() * / comparator() * |
LANGUAGE / I18NLEVEL=2 |
5255 |
GENURLAUTH / URLFETCH |
genurlauth() * / urlfetch() * |
URLAUTH |
4467 |
CONVERT |
fetch_convert() * |
CONVERT |
5259 |
FETCH ANNOTATION / STORE ANNOTATION |
fetch_annotation() * / store_annotation()
* |
ANNOTATE-EXPERIMENT-1 |
5257 |
SEARCH ... FUZZY |
fuzzy() criterion modifier * |
SEARCH=FUZZY |
6203 |
SEARCH ... FILTER |
filter_stored() criterion * |
FILTERS |
5466 |
APPEND size guard,
STATUS (APPENDLIMIT) |
automatic in append_msg()/append_msgs();
status(items = "APPENDLIMIT") |
APPENDLIMIT |
7889 |
| non-synchronizing literals | automatic on the raw-socket methods | LITERAL+ / LITERAL- |
7888 |
Every capability registered with IANA is covered. The methods marked
with an asterisk (*) are experimental: they follow the
RFC grammars, but no widely deployed server advertises those
capabilities (they are rare, brand new, or were never adopted), so they
could not be exercised against a live server. Availability of the others
varies by provider: Gmail, for instance, supports every non-experimental
extension above except SORT and
THREAD, which it has never implemented; to
exercise sort() and thread() you need a server
that advertises them (e.g. Dovecot-based hosts, Yandex, or
Outlook/Office 365). Announcement-only capabilities (AUTH=,
LOGINDISABLED, RIGHTS=, QUOTA=,
APPENDLIMIT=n,
MESSAGELIMIT=/SAVELIMIT=,
IMAPSIEVE=, JMAPACCESS,
INPROGRESS, CHILDREN,
I18NLEVEL=1, referrals) require no dedicated command and
are honored where they matter (folder listings, appends, error
reporting). UIDONLY (RFC 9586) responses
(UIDFETCH) are understood after
enable("UIDONLY"). The raw-socket methods
(idle(), notify(), append_msgs(),
append_catenate(), fetch_binary(),
replace_msg(), esearch_multi(),
urlfetch(), fetch_convert()) use TLS exactly
like the main connection: an imaps:// URL, or
use_ssl = TRUE on an imap:// URL
(STARTTLS).
# CRAN version
install.packages("mRpostman")
# Dev version
if (!require('remotes')) install.packages('remotes')
remotes::install_github("allanvc/mRpostman")mRpostman is built on the libcurl C library and requires
libcurl >= 7.58.0 (>= 7.65.0 for OAuth2.0 authentication) — any
recent Linux distribution satisfies this through
libcurl4-openssl-dev (deb) or libcurl-devel
(rpm); the macOS and Windows R builds already ship a suitable
version.
The package ships a disposable local IMAP server (Dovecot, in a Docker container) plus a deterministic synthetic corpus generator, so every feature can be exercised offline and reproducibly — no credentials, OAuth2 setup, or provider rate limits involved:
# after starting the container (see the "sandbox" vignette):
con <- configure_imap(url = "imap://localhost:1430", username = "testuser",
password = "sandbox", use_ssl = FALSE)
populate_sandbox(con, n = 200) # uploads the corpus with the package's own APPENDReal data works too: ingest_maildir() uploads any local
maildir-style directory to the server via APPEND, and
enron_sandbox() builds on it to download (once, with
consent, cached) the public Enron corpus and ingest a subset selected by
custodian, folder, and date — turning the sandbox into a full e-mail
data-analysis laboratory.
See the “A
reproducible IMAP sandbox with Docker” vignette for the guided
tour. The sandbox’s Dovecot server also advertises SORT and
THREAD, making it a convenient place to try the extensions
your provider may lack.
library(mRpostman)
con <- configure_imap(url = "imaps://outlook.office365.com",
username = "your_user@company.com",
password = rstudioapi::askForPassword())
# works with any provider from the table above (Gmail, Yahoo, Yandex, ...) and
# with self-hosted servers; use_uid, mute, and retries can also be set here,
# once, as connection-level defaults
con$list_server_capabilities()Most providers no longer accept plain account passwords from
third-party apps: you will typically authenticate with OAuth2.0 (the
xoauth2_bearer argument) or with an app-specific password
generated in your account’s security settings. The “Using
IMAP OAuth2.0 authentication in mRpostman” vignette covers the
OAuth2.0 setup for Gmail and other providers.
con$select_folder("INBOX")
# subject contains "budget" or "budget 3", and the message is unread
ids <- con$query((subject == "budget" | "budget 3") & flag != "SEEN")
# sent in Q4 2021 and larger than 5 MB
ids <- con$query(sent >= "2021-10-01" & sent < "2022-01-01" & size > 5e6)Fields cover subject, from,
to, body, text,
flag, size, age, the date
families, modseq, and header("Name"); see
?query for the full table. Raw protocol fragments enter
through verbatim(), as in
con$query(verbatim('X-GM-RAW "has:attachment"') & flag != "SEEN")
on Gmail. The pre-3.0.0 search_*() methods keep working as
deprecated spellings.
texts <- con$query(subject == "invoice" & age < 30 * 86400) %>%
con$fetch_text() %>%
clean_msg_text() # transfer encoding and charset decoded, plain character vectorids <- con$query(size > 1e6)
con$attachments_manifest(ids) # list without downloading
con$attachments(ids, dest = "~/att") # download, one folder per messageextract_attachments() does the same extraction offline,
from messages already fetched with fetch_body().
Server-side sort() and thread(), the
esearch_*() aggregates,
idle()/notify() push notifications, quota,
ACL, and the other IANA extensions are all methods on the same object;
the basics
vignette walks the full surface, and the sandbox
vignette lets you try everything against a local disposable server,
no account needed.
search results truncation: This is a libcurl’s
known bug which causes the search results to be truncated when there
is a large number of message ids returned. To circumvent this problem,
you can set a higher buffersize value, increasing the
buffer capacity, and verbose = TRUE for monitoring the
server response for truncated results when executing a search. When
possible, mRpostman tries to issue a warning for possible
truncated values.
verbose = TRUE malfunction on Windows: This
seems to be related to the {curl} R package.
When using the verbose = TRUE on Windows, the flow of
information between the IMAP server and the R session presents an
intermittent behavior, which causes it to not be shown on the console,
or with a considerable delay.
shared mailbox access not working: This seems to be another libcurl’s bug, although more tests need to be done to confirm it. It does not allow the user to connect to a shared mailbox. To circumvent this, if the shared mailbox has a password associated with it, you can try a direct regular connection.
xoauth2_bearer SASL error: This is related
to old libcurl’s versions
which causes the access token to not be properly passed to the server.
This bug was fixed in libcurl 7.65.0. The problem is that many Linux
distributions, such as Ubuntu 18.04, still provide libcurl 7.58.0 in
their official distribution (libcurl4-openssl-dev). If you use a newer
Linux distro such as Ubuntu 20.04, you should be fine as the distributed
libcurl’s version will be above 7.65.0. Another alternative is to use
plain authentication instead of OAuth2.0.
This package is licensed under the terms of the GPL-3 License.
Crispin, M. (2003), INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1, RFC 3501, March 2003, http.
Heinlein, P. and Hartleben, P. (2008). The Book of IMAP: Building a Mail Server with Courier and Cyrus. No Starch Press. ISBN 978-1-59327-177-0.
Ooms, J. (2020), curl: A Modern and Flexible Web Client for R. R package version 4.3, http.
Quadros, A. V. C. mRpostman: An IMAP Client for R, Journal of Open Research Software, vol. 12, no. 1, p. 4, 2024, doi: 10.5334/jors.480. http.
Stenberg, D. Libcurl - The Multiprotocol File Transfer Library, http.