mRpostman

CRAN_Status_Badge Downloads from the RStudio CRAN mirror Downloads from the RStudio CRAN mirror CRAN/METACRAN R-CMD-check

An IMAP Client for R

Overview

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").

Important changes in 3.0.0

Version 3.0.0 is the product of a deep refactoring of the package, and a few changes are not backward compatible:

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.

Providers and their IMAP urls

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.

Introduction

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:

Supported IMAP commands and capabilities

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().

Core commands (RFC 3501 — always available)

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()

Optional extensions (server-dependent — capability-checked)

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).

Installation

# 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.

Trying it without a mail account

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 APPEND

Real 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.

Basic Usage

1) Connect

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.

2) Search with plain R expressions

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.

3) Fetch the matches as analysis-ready text

texts <- con$query(subject == "invoice" & age < 30 * 86400) %>%
  con$fetch_text() %>%
  clean_msg_text() # transfer encoding and charset decoded, plain character vector

4) Attachments

ids <- con$query(size > 1e6)

con$attachments_manifest(ids)          # list without downloading
con$attachments(ids, dest = "~/att")   # download, one folder per message

extract_attachments() does the same extraction offline, from messages already fetched with fetch_body().

More

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.

Future Improvements

Known bugs

License

This package is licensed under the terms of the GPL-3 License.

References

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.