### Example imapfilter Configuration Source: https://github.com/lefcha/imapfilter/wiki/Docker A basic imapfilter configuration file written in Lua. It sets up an IMAP account and includes a loop for processing commands. ```lua myaccount = IMAP { username = 'user', password = 'secret', ssl = 'auto', } while true do myaccount.inbox:enter_idle() -- processing commands go here end ``` -------------------------------- ### Build imapfilter Docker Image Source: https://github.com/lefcha/imapfilter/wiki/Docker Use this Dockerfile to build an image containing the imapfilter application. It installs dependencies, clones the source code, builds, and installs imapfilter. ```dockerfile FROM debian:bullseye-slim RUN apt-get update && \ apt-get install -y make gcc git libssl-dev libpcre2-dev liblua5.4-dev && \ git clone https://github.com/lefcha/imapfilter.git && \ cd imapfilter && \ make -j INCDIRS=-I/usr/include/lua5.4/ LIBLUA=-llua5.4 && \ make install CMD ["/usr/local/bin/imapfilter", "-c", "/config.lua"] ``` -------------------------------- ### Compile imapfilter with Lua includes on Ubuntu Source: https://github.com/lefcha/imapfilter/wiki/Compiling-on-Ubuntu Use this command to compile imapfilter on Ubuntu, ensuring the Lua include path and library are correctly specified. Adjust the Lua version (e.g., lua5.3) to match your system's installation. ```bash make -j all INCDIRS=-I/usr/include/lua5.3 LIBLUA=-llua5.3 ``` -------------------------------- ### Copy Thread Messages to Another Mailbox Source: https://github.com/lefcha/imapfilter/wiki/Usefull-Lua-code-snippets-for-configurations An example of how to use the `thread_messages` function to find all messages in a thread and copy them to a different mailbox. Ensure the target mailbox exists. ```lua local mbox = account[mailbox_name] local my_messages = mbox:contain_from("my@email.com") for _, message in ipairs(my_messages) do local mailbox, uid = table.unpack(message) local my_related_messages = thread_messages(mailbox[uid], mbox) my_related_messages:copy_messages(account[another_mailbox_name]) end ``` -------------------------------- ### Enter IMAPFilter Interactive Mode Source: https://context7.com/lefcha/imapfilter/llms.txt Start IMAPFilter in interactive mode to experiment with commands or perform ad-hoc filtering tasks. This is useful for testing rules or managing mailboxes manually. ```bash imapfilter -i ``` -------------------------------- ### Get Message ID from a Message Object Source: https://github.com/lefcha/imapfilter/wiki/Usefull-Lua-code-snippets-for-configurations Extracts the Message-ID header from an imapfilter message object. It cleans up the header string. ```lua local function get_message_id(msg) local id = msg:fetch_field("Message-ID"):gsub("[Mm]essage%-[Ii][Dd]: ", "") return id end ``` -------------------------------- ### Get In-Reply-To ID from a Message Object Source: https://github.com/lefcha/imapfilter/wiki/Usefull-Lua-code-snippets-for-configurations Extracts the In-Reply-To header from an imapfilter message object. It cleans up the header string. ```lua local function get_reply_id(msg) local id = msg:fetch_field("In-Reply-To"):gsub("[Ii]n%-[Rr]eply%-[Tt]o: ", "") return id end ``` -------------------------------- ### Initialize IMAP Account with Plain Password Source: https://context7.com/lefcha/imapfilter/llms.txt Connect to an IMAP server using a username and plain text password. Ensure the password is kept secure. ```lua -- Plain password account1 = IMAP { server = 'imap.mail.server', username = 'alice', password = 'secret', } ``` -------------------------------- ### Build Docker Image Source: https://github.com/lefcha/imapfilter/wiki/Docker Build the Docker image using the Dockerfile. Ensure you are in the directory containing the Dockerfile. ```sh docker build -t imapfilter . ``` -------------------------------- ### Global Options Source: https://context7.com/lefcha/imapfilter/llms.txt The `options` table configures program-wide settings such as network timeouts, SSL handling, and IDLE keepalive intervals. ```APIDOC ## Global Options The `options` table controls program-wide behavior including network timeouts, SSL handling, expunge behavior, and IDLE keepalive intervals. ```lua -- $HOME/.imapfilter/config.lua options.timeout = 120 -- seconds to wait for server response (0 = block indefinitely) options.subscribe = true -- auto-subscribe newly created mailboxes options.expunge = true -- immediately expunge after marking deleted (default: true) options.close = false -- implicitly close/expunge mailbox after each operation options.namespace = true -- auto-apply server namespace prefix/delimiter options.charset = 'UTF-8' -- character set hint sent with search queries options.cache = true -- cache fetched message parts in memory for the session options.certificates = true -- store/validate server SSL certificates options.starttls = true -- negotiate STARTTLS if server supports it options.hostnames = true -- validate server hostname in SSL certificate options.keepalive = 29 -- minutes before re-issuing IDLE to reset server timeout options.limit = 50 -- max messages per request (workaround for picky servers) options.range = 50 -- max sequence number range per request options.info = true -- print summary of actions while processing options.wakeonany = false -- wake IDLE on any server event, not just new mail ``` ``` -------------------------------- ### Initialize IMAP Account with Custom Port and SSL/TLS Source: https://context7.com/lefcha/imapfilter/llms.txt Connect to an IMAP server on a non-standard port while enforcing a specific SSL/TLS version. This is useful for servers that do not use the default IMAPS port. ```lua -- Custom port account3 = IMAP { server = 'imap.corporate.net', username = 'alice', password = 'secret', port = 1993, ssl = 'tls1.2', } ``` -------------------------------- ### Run imapfilter with Default Configuration Source: https://context7.com/lefcha/imapfilter/llms.txt Executes imapfilter using the default configuration file located at $HOME/.imapfilter/config.lua. ```bash # Run with the default config ($HOME/.imapfilter/config.lua) imapfilter ``` -------------------------------- ### Initialize IMAP Account with Interactive Password Prompt Source: https://context7.com/lefcha/imapfilter/llms.txt Configure an IMAP account without storing the password directly in the configuration file. IMAPFilter will prompt the user for the password at runtime. ```lua -- Interactive password prompt (no password stored) account4 = IMAP { server = 'imap.example.com', username = 'bob', -- password omitted: imapfilter prompts at runtime } ``` -------------------------------- ### Makefile Configuration for GCC and Libraries Source: https://github.com/lefcha/imapfilter/wiki/OmniOS-illumos-(Solaris)-compilation-tips Configure the Makefile to use GCC as the C compiler, specify necessary libraries, and define library search paths. ```makefile CC = gcc ``` ```makefile MYLIBS = -lsocket ``` ```makefile LIBDIRS = -L/usr/local/lib ``` -------------------------------- ### Initialize IMAP Account with SSL/TLS Source: https://context7.com/lefcha/imapfilter/llms.txt Establish a secure connection to an IMAP server using SSL/TLS. The 'ssl' option can be set to 'auto', 'tls1.2', 'tls1.1', or 'tls1'. The default port for IMAPS is 993. ```lua -- SSL/TLS connection (port defaults to 993 for imaps) account2 = IMAP { server = 'imap.gmail.com', username = 'alice@gmail.com', password = 'apppassword', ssl = 'auto', -- 'auto' | 'tls1.2' | 'tls1.1' | 'tls1' } ``` -------------------------------- ### IMAP Account Initialization Source: https://context7.com/lefcha/imapfilter/llms.txt The `IMAP{}` function establishes a connection to an IMAP server, returning an account table for accessing mailboxes and invoking account-level methods. It supports plain passwords, interactive prompts, and OAuth2 strings for authentication. ```APIDOC ## IMAP Account Initialization — `IMAP{}` Establishes a connection to an IMAP server. Returns an account table used to access mailboxes and invoke account-level methods. Authentication can use a plain password, an interactively prompted password, or an OAuth2 string. ```lua -- Plain password account1 = IMAP { server = 'imap.mail.server', username = 'alice', password = 'secret', } -- SSL/TLS connection (port defaults to 993 for imaps) account2 = IMAP { server = 'imap.gmail.com', username = 'alice@gmail.com', password = 'apppassword', ssl = 'auto', -- 'auto' | 'tls1.2' | 'tls1.1' | 'tls1' } -- Custom port account3 = IMAP { server = 'imap.corporate.net', username = 'alice', password = 'secret', port = 1993, ssl = 'tls1.2', } -- Interactive password prompt (no password stored) account4 = IMAP { server = 'imap.example.com', username = 'bob', -- password omitted: imapfilter prompts at runtime } -- Password extracted from an external vault (e.g. pass) status, password = pipe_from('pass Email/imap.mail.server') password = password:gsub('[ ]', '') account5 = IMAP { server = 'imap.mail.server', username = 'alice', password = password, } ``` ``` -------------------------------- ### Managing Mailboxes with IMAP Source: https://context7.com/lefcha/imapfilter/llms.txt Provides functions to create, delete, rename, subscribe, and unsubscribe mailboxes on the server. Mailboxes can be created within existing folders. ```lua -- Create a new mailbox and subscribe to it account1:create_mailbox('Archive') account1:subscribe_mailbox('Archive') -- Create a mailbox inside a folder account1:create_mailbox('Lists/lua-users') account1:subscribe_mailbox('Lists/lua-users') -- Rename a mailbox account1:rename_mailbox('OldName', 'NewName') -- Unsubscribe then delete account1:unsubscribe_mailbox('Lists/old-list') account1:delete_mailbox('Lists/old-list') ``` -------------------------------- ### Run imapfilter with Custom Configuration Source: https://context7.com/lefcha/imapfilter/llms.txt Specifies a custom configuration file to be used by imapfilter. ```bash # Specify a custom config file imapfilter -c /etc/imapfilter/work.lua ``` -------------------------------- ### Listing Mailboxes Source: https://context7.com/lefcha/imapfilter/llms.txt Returns two tables: the available (or subscribed) mailboxes and folders under a given folder path. The wildcard `*` matches recursively; `%` matches within a single level. ```APIDOC ## Listing Mailboxes — `list_all()` / `list_subscribed()` Returns two tables: the available (or subscribed) mailboxes and folders under a given folder path. The wildcard `*` matches recursively; `%` matches within a single level. ```lua -- List all mailboxes at the root mailboxes, folders = account1:list_all() -- List subscribed mailboxes at the root mailboxes, folders = account1:list_subscribed() -- List inside a specific folder mailboxes, folders = account1:list_all('Lists') -- Use wildcard to find all mailboxes matching a pattern mailboxes, folders = account1:list_all('', 'work*') mailboxes, folders = account1:list_all('Lists', '*') -- Iterate results for _, mbox in ipairs(mailboxes) do print(mbox) end ``` ``` -------------------------------- ### pipe_from(command) Source: https://context7.com/lefcha/imapfilter/llms.txt Executes an external command and captures its standard output. ```APIDOC ## pipe_from(command) ### Description Executes an external command and captures its standard output. This is useful for retrieving dynamic data or secrets from external tools. ### Parameters - **command** (string) - Required - The command to execute (e.g., 'pass Email/imap.example.com' or 'curl -s https://api.example.com/check'). ### Returns - (number) - The exit status of the executed command. - (string) - The standard output captured from the command. ### Request Example ```lua -- Get password from a vault status, password = pipe_from('pass Email/imap.example.com') -- Get dynamic content from an API status, output = pipe_from('curl -s https://api.example.com/check') ``` ``` -------------------------------- ### Listing Mailboxes with IMAP Source: https://context7.com/lefcha/imapfilter/llms.txt Retrieves available or subscribed mailboxes and folders. Supports recursive (`*`) and single-level (`%`) wildcards for pattern matching. Results can be iterated. ```lua -- List all mailboxes at the root mailboxes, folders = account1:list_all() -- List subscribed mailboxes at the root mailboxes, folders = account1:list_subscribed() -- List inside a specific folder mailboxes, folders = account1:list_all('Lists') -- Use wildcard to find all mailboxes matching a pattern mailboxes, folders = account1:list_all('', 'work*') mailboxes, folders = account1:list_all('Lists', '*') -- Iterate results for _, mbox in ipairs(mailboxes) do print(mbox) end ``` -------------------------------- ### Initialize IMAP Account with Password from External Vault Source: https://context7.com/lefcha/imapfilter/llms.txt Retrieve the IMAP password from an external source, such as a password manager using the `pass_from` command. This enhances security by avoiding hardcoded credentials. ```lua -- Password extracted from an external vault (e.g. pass) status, password = pipe_from('pass Email/imap.mail.server') password = password:gsub('[ ]', '') account5 = IMAP { server = 'imap.mail.server', username = 'alice', password = password, } ``` -------------------------------- ### become_daemon(interval, function, [nochdir], [noclose]) Source: https://context7.com/lefcha/imapfilter/llms.txt Detaches the process from the terminal and runs a specified Lua function on a repeating interval. ```APIDOC ## become_daemon(interval, function, [nochdir], [noclose]) ### Description Transforms the current script into a background daemon process. The provided function is executed repeatedly at the specified interval. Optional flags control the working directory and standard I/O streams. ### Parameters - **interval** (number) - Required - The interval in seconds at which the function should be executed. - **function** (function) - Required - The Lua function to execute periodically. - **nochdir** (boolean, optional) - If `true`, the current working directory is not changed. - **noclose** (boolean, optional) - If `true`, standard input, output, and error streams are not closed. ### Request Example ```lua function process_mail() -- ... mail processing logic ... end -- Run process_mail every 10 minutes become_daemon(600, process_mail) -- Run with options to keep CWD and stdio open become_daemon(600, process_mail, true, true) ``` ``` -------------------------------- ### Fetch Message Headers and Size Source: https://context7.com/lefcha/imapfilter/llms.txt Iterate over messages to fetch specific fields like Subject and From, as well as the message size. Requires messages to be selected first. ```lua -- Iterate over unseen messages and inspect headers results = account1.INBOX:is_unseen() for _, message in ipairs(results) do mailbox, uid = table.unpack(message) subject = mailbox[uid]:fetch_field('Subject') from = mailbox[uid]:fetch_field('From') size = mailbox[uid]:fetch_size() print(string.format('UID %d | Size: %d | %s | %s', uid, size, from, subject)) end ``` -------------------------------- ### Configure IMAPFilter Global Options Source: https://context7.com/lefcha/imapfilter/llms.txt Set program-wide behavior for IMAPFilter, such as network timeouts, SSL handling, and IDLE keepalive intervals. These options are defined in the `$HOME/.imapfilter/config.lua` file. ```lua -- $HOME/.imapfilter/config.lua options.timeout = 120 -- seconds to wait for server response (0 = block indefinitely) options.subscribe = true -- auto-subscribe newly created mailboxes options.expunge = true -- immediately expunge after marking deleted (default: true) options.close = false -- implicitly close/expunge mailbox after each operation options.namespace = true -- auto-apply server namespace prefix/delimiter options.charset = 'UTF-8' -- character set hint sent with search queries options.cache = true -- cache fetched message parts in memory for the session options.certificates = true -- store/validate server SSL certificates options.starttls = true -- negotiate STARTTLS if server supports it options.hostnames = true -- validate server hostname in SSL certificate options.keepalive = 29 -- minutes before re-issuing IDLE to reset server timeout options.limit = 50 -- max messages per request (workaround for picky servers) options.range = 50 -- max sequence number range per request options.info = true -- print summary of actions while processing options.wakeonany = false -- wake IDLE on any server event, not just new mail ``` -------------------------------- ### Pipe IMAPFilter Configuration via Stdin Source: https://context7.com/lefcha/imapfilter/llms.txt Provide a full IMAPFilter configuration file to the tool by piping its content via standard input. This is useful for managing complex configurations or integrating with scripting workflows. ```bash cat myconfig.lua | imapfilter -c - ``` -------------------------------- ### Capture Output from External Program Source: https://context7.com/lefcha/imapfilter/llms.txt Executes an external command and captures its stdout. Useful for retrieving passwords from vaults or fetching dynamic content. ```lua -- Read a password from a vault status, password = pipe_from('pass Email/imap.example.com') password = password:gsub('[ ]', '') -- Or get dynamic content for decisions status, output = pipe_from('curl -s https://api.example.com/check') ``` -------------------------------- ### Searching Messages by Regex (PCRE, Case-Sensitive, Local) Source: https://context7.com/lefcha/imapfilter/llms.txt Perform local, case-sensitive regular expression matching (PCRE) on message parts after downloading them. ```APIDOC ## Searching Messages — Regex (PCRE, case-sensitive, local) Regular expression matching downloads message parts locally and matches via PCRE. Use with meta-searching to minimize downloads. ### Match From header with a PCRE pattern ```lua results = account1.INBOX:match_from('.*(user1|user2)@example\.com') ``` ### Match Subject with a pattern ```lua results = account1.INBOX:match_subject('^\[PATCH( v\d+)?\]') ``` ### Match an arbitrary header field ```lua results = account1.INBOX:match_field('X-Mailer', 'Outlook.*2019') ``` ### Match the full header block ```lua results = account1.INBOX:match_header('^.+MailScanner.*Check: [Ss]pam$') ``` ### Match message body ```lua results = account1.INBOX:match_body('(?i)free.*money|win.*prize') ``` ### Match the full message ```lua results = account1.INBOX:match_message('^[Hh]ello world!?$') ``` ### Efficient pattern: narrow with server-side search, then PCRE locally ```lua results = account1.INBOX:is_unseen():match_header('^.+MailScanner.*Check: [Ss]pam$') results:delete_messages() ``` ``` -------------------------------- ### Execute IMAPFilter One-Liner Source: https://context7.com/lefcha/imapfilter/llms.txt Use this to quickly execute a single IMAPFilter rule from the command line without a separate configuration file. Ensure your account details and filter logic are correctly formatted. ```bash imapfilter -e "account1 = IMAP{server='imap.example.com',username='alice',password='pw'} account1.INBOX:is_old():delete_messages()" ``` -------------------------------- ### Fetch Full Message, Header, or Body Source: https://context7.com/lefcha/imapfilter/llms.txt Retrieve the entire message, just the header, or only the body content for a specific message identified by its mailbox and UID. ```lua -- Fetch full message, header, or body msg = account1.mymailbox[22]:fetch_message() header = account1.mymailbox[22]:fetch_header() body = account1.mymailbox[22]:fetch_body() ``` -------------------------------- ### Mark Messages as Seen Source: https://context7.com/lefcha/imapfilter/llms.txt Mark messages as read. This operation applies the \Seen flag to the selected messages. ```lua -- Mark as seen (read) results = account1.INBOX:is_new() results:mark_seen() ``` -------------------------------- ### Run imapfilter Docker Container Source: https://github.com/lefcha/imapfilter/wiki/Docker Run the imapfilter Docker container, mounting your local configuration file to the expected path inside the container. This allows imapfilter to use your custom settings. ```sh docker run -v ~/.imapfilter/config.lua:/config.lua imapfilter ``` -------------------------------- ### Mailbox Management Source: https://context7.com/lefcha/imapfilter/llms.txt Creates, removes, renames, subscribes, or unsubscribes mailboxes on the server. ```APIDOC ## Mailbox Management — `create_mailbox()`, `delete_mailbox()`, `rename_mailbox()`, `subscribe_mailbox()`, `unsubscribe_mailbox()` Creates, removes, renames, subscribes, or unsubscribes mailboxes on the server. ```lua -- Create a new mailbox and subscribe to it account1:create_mailbox('Archive') account1:subscribe_mailbox('Archive') -- Create a mailbox inside a folder account1:create_mailbox('Lists/lua-users') account1:subscribe_mailbox('Lists/lua-users') -- Rename a mailbox account1:rename_mailbox('OldName', 'NewName') -- Unsubscribe then delete account1:unsubscribe_mailbox('Lists/old-list') account1:delete_mailbox('Lists/old-list') ``` ``` -------------------------------- ### Wrap Function with Recovery Mechanism Source: https://context7.com/lefcha/imapfilter/llms.txt Wraps a function to automatically retry execution with exponential backoff on errors. Optionally limits the number of retries and handles success/failure reporting. ```lua -- Retry indefinitely on failure function commands() results = account1.INBOX:is_old() results:move_messages(account1.Archive) end recover(commands) ``` ```lua -- Retry up to 5 times, then give up recover(commands, 5) ``` ```lua -- Handle return value and error message success, errormsg = recover(commands, 5) if not success then print('Failed after retries: ' .. tostring(errormsg)) end ``` ```lua -- Multi-account daemon: independent recovery per account function account1_tasks() account1.INBOX:is_old():move_messages(account1.Archive) end function account2_tasks() account2.INBOX:is_seen():delete_messages() end while true do recover(account1_tasks, 4) -- each account recovers independently recover(account2_tasks, 2) sleep(600) end ``` -------------------------------- ### OAuth2 Authentication with IMAP Source: https://context7.com/lefcha/imapfilter/llms.txt Authenticates using the XOAUTH2 mechanism. Requires an externally generated OAuth2 string. The password field can be used as a fallback if the server does not support XOAUTH2. ```lua -- Generate a fresh access token and OAuth2 string using oauth2.py -- (https://github.com/google/gmail-oauth2-tools) user = 'alice@gmail.com' clientid = '364545978226.apps.googleusercontent.com' clientsecret = 'zNrNsBzOOnQy8_O-8LkofeTR' refreshtoken = '1/q4SaB2JMQB9I-an6F1rxJE9OkOMtfjaz1bPm1tfDpQM' status, output = pipe_from('oauth2.py --client_id=' .. clientid .. ' --client_secret=' .. clientsecret .. ' --refresh_token=' .. refreshtoken) _, _, accesstoken = string.find(output, 'Access Token: ([%w%p]+)\n') status, output = pipe_from('oauth2.py --generate_oauth2_string' .. ' --access_token=' .. accesstoken .. ' --user=' .. user) _, _, oauth2string = string.find(output, 'OAuth2 argument:\n([%w%p]+)\n') gmail = IMAP { server = 'imap.gmail.com', ssl = 'tls1.2', username = user, oauth2 = oauth2string, -- password = 'fallback' -- used if server lacks XOAUTH2 } ``` -------------------------------- ### Fetch Specific MIME Parts Source: https://context7.com/lefcha/imapfilter/llms.txt Fetch the MIME structure of a message to identify different parts (e.g., text/plain, images), then retrieve specific parts by their ID. Useful for selectively downloading content. ```lua -- Fetch MIME body structure, then specific parts structure = account1.mymailbox[22]:fetch_structure() -- structure = { ["1"] = {type="text/plain", size=512}, ["2"] = {type="image/png", size=40960, name="logo.png"}, ... } for partid, partinf in pairs(structure) do if partinf.type:lower() == 'text/plain' and partinf.size < 1024 then text = account1.mymailbox[22]:fetch_part(partid) print(text) end end ``` -------------------------------- ### Run imapfilter with Debug Logging Source: https://context7.com/lefcha/imapfilter/llms.txt Enables debug mode for imapfilter, dumping the full IMAP protocol exchange to a specified log file. ```bash # Debug: dump full IMAP protocol exchange to a file imapfilter -d /tmp/imap-debug.log ``` -------------------------------- ### Run imapfilter in Verbose Mode Source: https://context7.com/lefcha/imapfilter/llms.txt Enables verbose output for imapfilter, printing brief details of server communication. ```bash # Verbose: print brief server communication details imapfilter -v ``` -------------------------------- ### pipe_to(command, data) Source: https://context7.com/lefcha/imapfilter/llms.txt Pipes the provided data string to an external command and returns its exit status. ```APIDOC ## pipe_to(command, data) ### Description Executes an external command and provides the given data string as its standard input. It returns the command's exit status. ### Parameters - **command** (string) - Required - The command to execute (e.g., 'spamassassin -e'). - **data** (string) - Required - The data to pipe as standard input to the command. ### Returns - (number) - The exit status of the executed command. ### Request Example ```lua -- Check if a message is spam using spamassassin if pipe_to('spamassassin -e', text) == 1 then print('Message is spam') end ``` ``` -------------------------------- ### get_password(prompt) Source: https://context7.com/lefcha/imapfilter/llms.txt Prompts the user interactively for a password, suppressing character echo. ```APIDOC ## get_password(prompt) ### Description Displays a prompt to the user and reads a password from standard input without echoing the characters typed. This is useful for securely obtaining credentials at runtime. ### Parameters - **prompt** (string) - Required - The message to display to the user before prompting for input. ### Returns - (string) - The password entered by the user. ### Request Example ```lua pwd = get_password('Enter IMAP password for alice@example.com: ') ``` ``` -------------------------------- ### Interactive Password Prompt Source: https://context7.com/lefcha/imapfilter/llms.txt Prompts the user for a password at runtime with character echo suppressed. The entered password can then be used for authentication. ```lua -- Prompt the user at runtime; character echo is suppressed pwd = get_password('Enter IMAP password for alice@example.com: ') account1 = IMAP { server = 'imap.example.com', username = 'alice', password = pwd } ``` -------------------------------- ### Configure IMAPFilter with Custom SSL Trust Store Source: https://context7.com/lefcha/imapfilter/llms.txt Specify a custom path to your SSL certificate trust store when running IMAPFilter. This is necessary if you are connecting to servers with self-signed certificates or a non-standard CA. ```bash imapfilter -t /etc/ssl/certs/ca-certificates.crt ``` -------------------------------- ### Modify PATH for GNU Tools Source: https://github.com/lefcha/imapfilter/wiki/OmniOS-illumos-(Solaris)-compilation-tips Prepend the directory containing GNU tools to your PATH environment variable to ensure they are used before native system utilities. ```shell export PATH=/usr/local/gnu:$PATH ``` -------------------------------- ### Add IMAP System Flags Source: https://context7.com/lefcha/imapfilter/llms.txt Add one or more standard IMAP system flags to messages. Use double backslashes for system flags like \Seen and \Flagged. ```lua -- Add multiple flags at once (use double backslash for system flags) results = account1.INBOX:is_recent() results:add_flags({ '\Seen', '\Flagged' }) ``` -------------------------------- ### Raw IMAP Query — `send_query()` Source: https://context7.com/lefcha/imapfilter/llms.txt Send raw IMAP SEARCH criteria strings directly to the server for searching messages. ```APIDOC ## Raw IMAP Query — `send_query()` Sends a raw IMAP SEARCH criteria string (RFC 3501 §6.4.4) to the server. ### Get all messages ```lua results = account1.INBOX:send_query('ALL') ``` ### Get unread messages from a specific sender ```lua results = account1.INBOX:send_query('UNSEEN FROM "boss@company.com"') ``` ### Get messages with a specific header ```lua results = account1.INBOX:send_query('HEADER X-Priority 1') ``` ### Get large unseen messages ```lua results = account1.INBOX:send_query('UNSEEN LARGER 1000000') ``` ``` -------------------------------- ### Searching Messages by Header Content (Case-Insensitive) Source: https://context7.com/lefcha/imapfilter/llms.txt Search header fields and message body using case-insensitive substring matching on the server. ```APIDOC ## Searching Messages — Header Content (case-insensitive) Search header fields and message body using substring matching (server-side, case-insensitive). ### Messages from a specific sender ```lua results = account1.INBOX:contain_from('announce@my.unix.os') ``` ### Messages with a specific subject ```lua results = account1['lists/devel']:contain_subject('[patch]') ``` ### Messages to a specific recipient ```lua results = account1.INBOX:contain_to('alice@example.com') ``` ### Messages with CC or BCC recipients ```lua results = account1.INBOX:contain_cc('team@example.com') results = account1.INBOX:contain_bcc('hidden@example.com') ``` ### Search an arbitrary header field ```lua results = account1.INBOX:contain_field('X-Spam-Flag', 'YES') results = account1.INBOX:contain_field('Sender', 'owner@announce-list') ``` ### Search message body or full message content ```lua results = account1.INBOX:contain_body('unsubscribe') results = account1.INBOX:contain_message('click here to unsubscribe') ``` ### Practical example: move newsletters to a folder ```lua results = account1.INBOX:is_unseen() * account1.INBOX:contain_from('weekly-news@news.letter') results:copy_messages(account1.newsletters) results:mark_seen() ``` ``` -------------------------------- ### Raw IMAP Query Search Source: https://context7.com/lefcha/imapfilter/llms.txt Send raw IMAP SEARCH criteria strings directly to the server using `send_query()`. This allows for complex searches not directly exposed by imapfilter's helper functions. ```lua -- All messages results = account1.INBOX:send_query('ALL') -- Unread messages from a specific sender (raw IMAP syntax) results = account1.INBOX:send_query('UNSEEN FROM "boss@company.com"') -- Messages with a specific header results = account1.INBOX:send_query('HEADER X-Priority 1') -- Large unseen messages results = account1.INBOX:send_query('UNSEEN LARGER 1000000') ``` -------------------------------- ### recover(function, [retries]) Source: https://context7.com/lefcha/imapfilter/llms.txt Wraps a function to provide automatic retries with exponential backoff on errors. ```APIDOC ## recover(function, [retries]) ### Description Executes a given function and automatically retries its execution with exponential backoff in case of any errors (e.g., network issues, IMAP errors). Optionally, a maximum number of retries can be specified. ### Parameters - **function** (function) - Required - The Lua function to execute and protect with recovery logic. - **retries** (number, optional) - The maximum number of times to retry the function execution. If omitted, retries indefinitely. ### Returns - (boolean) - `true` if the function executed successfully, `false` otherwise. - (string, optional) - An error message if the function failed after all retries. ### Request Example ```lua function commands() -- ... commands to execute ... end -- Retry indefinitely recover(commands) -- Retry up to 5 times success, errormsg = recover(commands, 5) if not success then print('Failed after retries: ' .. tostring(errormsg)) end ``` ``` -------------------------------- ### Recursively Fetch All Messages in a Thread Source: https://github.com/lefcha/imapfilter/wiki/Usefull-Lua-code-snippets-for-configurations Recursively finds all messages belonging to the same email thread as a given message. It requires helper functions to fetch message IDs and reply-to IDs. ```lua local function get_message_id(msg) local id = msg:fetch_field("Message-ID"):gsub("[Mm]essage%-[Ii][Dd]: ", "") return id end local function get_reply_id(msg) local id = msg:fetch_field("In-Reply-To"):gsub("[Ii]n%-[Rr]eply%-[Tt]o: ", "") return id end function thread_messages(msg, mbox, related_messages, examined_ids) -- initilize examined_ids in case it's the first call of this function if not examined_ids then examined_ids = {} end -- This message local this_msgid = get_message_id(msg) table.insert(examined_ids, this_msgid) local this_message = mbox:match_field("Message-ID", this_msgid) -- The messages directly replyed to our `msg` local currently_related_messages = mbox:match_field("In-Reply-To", this_msgid) if related_messages then related_messages = related_messages + currently_related_messages else related_messages = currently_related_messages end -- The messages our `msg` was replyed to local prev_msgid = get_reply_id(msg) if string.len(prev_msgid) > 1 then related_messages = related_messages + mbox:match_field("Message-ID", prev_msgid) end -- Recursively add up messages related in the same way to the related_messages for _, related_msg in ipairs(related_messages) do local mailbox_related, uid_related = table.unpack(related_msg) local related_msgid = get_message_id(mailbox_related[uid_related]) -- will check for every known related message if the messages replyed to `related_msgid` have been examined local skip = false for i=1,#examined_ids do if related_msgid == examined_ids[i] then skip = true end end if not skip then related_messages = related_messages + thread_messages(mailbox_related[uid_related], mbox, related_messages, examined_ids) end end return related_messages + this_message end ``` -------------------------------- ### IMAP IDLE Extension for Real-time Notifications Source: https://context7.com/lefcha/imapfilter/llms.txt Implements the IMAP IDLE extension (RFC 2177) to receive mailbox change notifications without polling. Blocks until a change occurs or is interrupted. Handles servers without IDLE support by falling back to polling. ```lua -- Basic IDLE loop: wake on new mail, process, repeat while true do account1.INBOX:enter_idle() results = account1.INBOX:is_unseen() results:move_messages(account1.Unread) end -- Check return values; handle servers without IDLE support while true do update, event = account1.INBOX:enter_idle() if not update then -- Server does not support IDLE; fall back to polling sleep(300) else print('Woke on event: ' .. tostring(event)) results = account1.INBOX:is_unseen() results:move_messages(account1.Unread) end end -- Robust IDLE that skips wait when unseen messages already exist function custom_idle(mbox) if #mbox:is_unseen() == 0 then if not mbox:enter_idle() then sleep(300) end end end while true do custom_idle(account1.INBOX) account1.INBOX:is_unseen():move_messages(account1.Unread) end ``` -------------------------------- ### Pipe Data to External Program Source: https://context7.com/lefcha/imapfilter/llms.txt Sends data to an external command via stdin. Useful for processing messages with external tools like spam classifiers. Returns the exit code of the command. ```lua -- Pass each message through a spam classifier; delete positives all = account1.INBOX:select_all() results = Set {} for _, mesg in ipairs(all) do mbox, uid = table.unpack(mesg) text = mbox[uid]:fetch_message() if pipe_to('spamassassin -e', text) == 1 then table.insert(results, mesg) end end results:delete_messages() ``` -------------------------------- ### Fetch Message Flags and Internal Date Source: https://context7.com/lefcha/imapfilter/llms.txt Retrieve the IMAP flags and the internal date of a message. Flags are returned as a table of strings, and the date as a string. ```lua -- Fetch flags and internal date flags = account1.mymailbox[22]:fetch_flags() -- returns table of strings date = account1.mymailbox[22]:fetch_date() -- returns string ``` -------------------------------- ### Search Messages by Regex (PCRE) Source: https://context7.com/lefcha/imapfilter/llms.txt Perform case-sensitive regular expression matching on message parts locally. Use with server-side searches to minimize data transfer. Requires double backslashes for Lua strings. ```lua -- Match From header with a PCRE pattern (note double backslashes for Lua) results = account1.INBOX:match_from('.*(user1|user2)@example\.com') -- Match Subject with a pattern results = account1.INBOX:match_subject('^\[PATCH( v\d+)?\]') -- Match any header field results = account1.INBOX:match_field('X-Mailer', 'Outlook.*2019') -- Match full header block results = account1.INBOX:match_header('^.+MailScanner.*Check: [Ss]pam$') -- Match body results = account1.INBOX:match_body('(?i)free.*money|win.*prize') -- Match full message results = account1.INBOX:match_message('^[Hh]ello world!?$') -- Efficient pattern: first narrow with server-side search, then PCRE locally results = account1.INBOX:is_unseen():match_header('^.+MailScanner.*Check: [Ss]pam$') results:delete_messages() ``` -------------------------------- ### Search Messages by Date Source: https://context7.com/lefcha/imapfilter/llms.txt Filter messages by their arrival date or sent date using a specific format ('DD-Mon-YYYY'). Relative dates can be calculated using `form_date()`. ```lua -- Messages that arrived on or after 1 Jan 2024 results = account1.INBOX:arrived_since('01-Jan-2024') -- Messages sent before a specific date results = account1.INBOX:sent_before('01-Jun-2023') -- Messages arrived on an exact date results = account1.INBOX:arrived_on('25-Dec-2023') -- Use form_date() to compute a relative date (N days ago) cutoff = form_date(90) -- returns "DD-Mon-YYYY" for 90 days ago results = account1.INBOX:arrived_before(cutoff) results:move_messages(account1.Archive) -- Combined: sent in a date range results = account1.INBOX:sent_since('01-Jan-2024') * account1.INBOX:sent_before('01-Feb-2024') ``` -------------------------------- ### Meta-Searching Mailbox Results Source: https://context7.com/lefcha/imapfilter/llms.txt Narrow down existing search results by applying search methods directly to the result set instead of the entire mailbox. This allows for more granular filtering. ```lua -- Get unseen messages, then filter locally with PCRE results = account1.INBOX:is_unseen() spam = results:match_header('^.+MailScanner.*Check: [Ss]pam$') spam:delete_messages() ``` ```lua -- Method chaining (one-liner) account1.INBOX:is_new():match_body('^[Ww]orld, hello!?$'):delete_messages() ``` ```lua -- Narrow by size, then by regex in body results = account1.INBOX:is_larger(50000):match_body('bitcoin wallet') results:delete_messages() ``` -------------------------------- ### regex_search(pattern, string) Source: https://context7.com/lefcha/imapfilter/llms.txt Performs a PCRE (Perl Compatible Regular Expressions) search on a string and returns capture groups. ```APIDOC ## regex_search(pattern, string) ### Description Searches a given string for a match against a PCRE pattern. It returns whether a match was found and any captured subpatterns. ### Parameters - **pattern** (string) - Required - The PCRE pattern to search for. - **string** (string) - Required - The string to search within. ### Returns - (boolean) - `true` if a match is found, `false` otherwise. - (string, optional) - The content of the first capture group, if any. - (string, optional) - The content of subsequent capture groups, if any. ### Request Example ```lua -- Extract sender from a header line matched, capture = regex_search('^From: (.+)$', header_line) if matched then print('Sender: ' .. capture) end -- Extract user and domain from an email address ok, user, domain = regex_search('^([\w.+-]+)@([\w.-]+)$', 'alice@example.com') -- ok=true, user="alice", domain="example.com" ``` ``` -------------------------------- ### append_message() Source: https://context7.com/lefcha/imapfilter/llms.txt Uploads a raw message string to a mailbox, with options to preserve original flags and date. ```APIDOC ## append_message(raw_message_string, [flags], [date]) ### Description Appends a raw email message to a specified mailbox. It can optionally preserve the original message flags and date. ### Parameters - **raw_message_string** (string) - Required - The raw content of the email message to append. - **flags** (table, optional) - The original flags to preserve for the appended message. - **date** (string, optional) - The original date to preserve for the appended message. ### Request Example ```lua -- Append a message with no metadata account1.Archive:append_message(raw_message_string) -- Append a message preserving flags and date account2.INBOX:append_message(msg, flags, date) ``` ``` -------------------------------- ### Append Raw Message to Mailbox Source: https://context7.com/lefcha/imapfilter/llms.txt Uploads a raw message string to a specified mailbox. Optionally preserves original flags and date when migrating messages between servers. ```lua -- Append a message with no metadata account1.Archive:append_message(raw_message_string) ``` ```lua -- Copy-transform: fetch, add a custom header, re-upload all = account1.mymailbox:select_all() for _, mesg in ipairs(all) do mbox, uid = table.unpack(mesg) header = mbox[uid]:fetch_header() body = mbox[uid]:fetch_body() message = header:gsub('[ ]+$', ' ') .. 'X-Processed: imapfilter ' .. ' ' .. body account1.Processed:append_message(message) end ``` ```lua -- Cross-server migration preserving flags and date results = account1.INBOX:select_all() for _, mesg in ipairs(results) do mbox, uid = table.unpack(mesg) msg = mbox[uid]:fetch_message() flags = mbox[uid]:fetch_flags() date = mbox[uid]:fetch_date() account2.INBOX:append_message(msg, flags, date) end ``` -------------------------------- ### Combine Searches Across Mailboxes Source: https://context7.com/lefcha/imapfilter/llms.txt Use the '+' operator to combine search results from different mailboxes or accounts. The '*' operator can be used for AND logic between search criteria within the same mailbox. ```lua -- OR: unseen from two different mailboxes (same account) results = account1.INBOX:is_unseen() + account1['Lists/lua']:is_unseen() ``` ```lua -- Combine results from two separate accounts all_recent = account1.INBOX:is_recent() + account2.INBOX:is_recent() all_recent:add_flags({ '\Seen', '\Flagged' }) ``` ```lua -- Cross-account move results = account1.INBOX:contain_from('boss@old-company.com') results:move_messages(account2['Archive/old-job']) ``` ```lua -- Reusable filter function with parameters myfilter = function(mailbox, size, subject) return mailbox:is_unseen() + mailbox:is_larger(size) * mailbox:contain_subject(subject) end results = myfilter(account1.INBOX, 100000, 'newsletter') results:move_messages(account1.Newsletters) ``` -------------------------------- ### Search Messages by Size and Age Source: https://context7.com/lefcha/imapfilter/llms.txt Filter messages based on their size in octets or their age in days. This is useful for cleaning up large or old emails. Operations can be combined. ```lua -- Messages larger than 5 MB large = account1.INBOX:is_larger(5 * 1024 * 1024) -- Messages smaller than 10 KB small = account1.INBOX:is_smaller(10240) -- Messages older than 30 days old = account1.INBOX:is_older(30) -- Messages newer than 7 days recent_week = account1.INBOX:is_newer(7) -- Delete large old messages: older than 90 days AND larger than 10 MB results = account1.INBOX:is_older(90) * account1.INBOX:is_larger(10 * 1024 * 1024) results:delete_messages() ```