### Install mail suite with optional dependencies Source: https://github.com/seanthegeek/mailsuite/blob/master/AGENTS.md Install the mailsuite library in editable mode with support for Microsoft Graph and Gmail APIs. Also installs development tools like pytest and ruff. ```bash pip install -e ".[msgraph,gmail]" pip install pytest pytest-cov ruff pyright ``` -------------------------------- ### Install MailSuite with All Optional Extras Source: https://github.com/seanthegeek/mailsuite/blob/master/README.md Install MailSuite with all optional extras, including both Microsoft Graph and Gmail backends. ```bash pip install "mailsuite[all]" ``` -------------------------------- ### Install MailSuite with Extras Source: https://context7.com/seanthegeek/mailsuite/llms.txt Install the base package or with optional extras for cloud provider support like Microsoft Graph or Gmail. ```bash pip install mailsuite ``` ```bash pip install "mailsuite[msgraph]" ``` ```bash pip install "mailsuite[gmail]" ``` ```bash pip install "mailsuite[all]" ``` -------------------------------- ### Install MailSuite with Gmail Support Source: https://github.com/seanthegeek/mailsuite/blob/master/README.md Install MailSuite with the optional Gmail backend, which includes the google-api-python-client and google-auth-oauthlib libraries. ```bash pip install "mailsuite[gmail]" ``` -------------------------------- ### Install MailSuite Base Package Source: https://github.com/seanthegeek/mailsuite/blob/master/README.md Install the core MailSuite package for IMAP, SMTP, DKIM, Maildir, and email parsing functionalities. ```bash pip install mailsuite ``` -------------------------------- ### Install MailSuite with Gmail Support Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Install the MailSuite library with the 'gmail' extra to enable Gmail API integration. This is required for certain Gmail-specific functionalities. ```bash pip install mailsuite[gmail] ``` -------------------------------- ### Install MailSuite with Microsoft Graph Support Source: https://github.com/seanthegeek/mailsuite/blob/master/README.md Install MailSuite with the optional Microsoft Graph backend, which includes the necessary msgraph-sdk and azure-identity libraries. ```bash pip install "mailsuite[msgraph]" ``` -------------------------------- ### MS Graph Mailbox Connection Setup Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Initialize a MailboxConnection using Microsoft Graph authentication. Requires the 'msgraph' extra and specific API permissions. ```python pip install mailsuite[msgraph] ``` -------------------------------- ### Fetch Messages in Folder Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Get a list of message identifiers within a specified folder. ```python fetch_messages(reports_folder: str, **kwargs: Any) → list ``` -------------------------------- ### MSGraphConnection: App-only Authentication Source: https://context7.com/seanthegeek/mailsuite/llms.txt Configures `MSGraphConnection` using the ClientSecret authentication flow for app-only access. Requires `pip install mailsuite[msgraph]`. Ensure `allow_unencrypted_storage` is set appropriately for token caching. ```python from mailsuite.mailbox import MSGraphConnection from mailsuite.utils import parse_email # App-only (daemon / service) — ClientSecret flow conn = MSGraphConnection( auth_method="ClientSecret", mailbox="reports@example.com", client_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", client_secret="super_secret_value", username=None, password=None, tenant_id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy", token_file="/var/lib/myapp/graph_token.json", allow_unencrypted_storage=False, ) ``` -------------------------------- ### Configure MSGraphConnection Token Cache Name Source: https://github.com/seanthegeek/mailsuite/blob/master/README.md To maintain authentication across installations or migrations, specify a custom token cache name using `token_cache_name` for `MSGraphConnection`. This ensures existing cached authentication records and tokens are recognized. ```python token_cache_name="parsedmarc") ``` -------------------------------- ### DKIM Get Public Key Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Derives the DKIM public key from a given private key. The output is base64-encoded and suitable for the `p=` tag in a DKIM TXT record. ```APIDOC ## mailsuite.dkim.get_dkim_public_key ### Description Derives the DKIM public key from a private key. The returned key is base64-encoded. ### Parameters * **private_key** (str | bytes) - Required - A PEM-encoded RSA private key (PKCS#1 or PKCS#8). ### Returns * **str** - A base64-encoded `SubjectPublicKeyInfo` value. ``` -------------------------------- ### Initialize MSGraphConnection with DeviceCode flow Source: https://context7.com/seanthegeek/mailsuite/llms.txt Instantiate MSGraphConnection for delegated authentication using the DeviceCode flow. Requires mailbox, client ID, and tenant ID. Token storage is configured with allow_unencrypted_storage. ```python delegated = MSGraphConnection( auth_method="DeviceCode", mailbox="user@example.com", client_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", client_secret=None, username="user@example.com", password=None, tenant_id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy", token_file="~/.mailsuite/token.json", allow_unencrypted_storage=True, # Sovereign cloud: # graph_url="https://graph.microsoft.us", ) ``` -------------------------------- ### Initialize GmailConnection for OAuth2 flow Source: https://context7.com/seanthegeek/mailsuite/llms.txt Set up GmailConnection for the installed-app OAuth2 flow. Requires token and credentials files, and specifies scopes for Gmail API access. Includes options for spam/trash inclusion, report folder, and polling timeout. ```python from mailsuite.mailbox import GmailConnection from mailsuite.utils import parse_email SCOPES = [ "https://www.googleapis.com/auth/gmail.modify", "https://www.googleapis.com/auth/gmail.send", ] conn = GmailConnection( token_file="token.json", credentials_file="credentials.json", # OAuth2 client secrets from Google Cloud Console scopes=SCOPES, include_spam_trash=False, reports_folder="INBOX", oauth2_port=8080, paginate_messages=True, auth_mode="installed_app", # or "service_account" # service_account_user="user@example.com", # for service account impersonation ) ``` -------------------------------- ### IMAPClient - IMAP IDLE (Push Notifications) Source: https://context7.com/seanthegeek/mailsuite/llms.txt Demonstrates setting up IMAP IDLE for real-time push notifications of new messages, including a callback function to process incoming mail. ```APIDOC ## IMAPClient IDLE (Push Notifications) Set up a callback for new mail notifications: ```python def on_new_mail(imap_client: IMAPClient): uids = imap_client.search() for uid in uids: msg = imap_client.fetch_message(uid, parse=True) print("New message:", msg["subject"]) imap_client.move_messages([uid], "Processed") # Blocks until KeyboardInterrupt; auto-refreshes IDLE every 5 minutes IMAPClient( host="imap.example.com", username="user@example.com", password="secret", idle_callback=on_new_mail, idle_timeout=30, ) ``` ``` -------------------------------- ### Send Email with Explicit TLS Source: https://context7.com/seanthegeek/mailsuite/llms.txt Use this function to send emails over an encrypted TLS connection from the start. Ensure the host and port are configured for explicit TLS (commonly port 465). ```python send_email( host="smtp.example.com", port=465, require_encryption=True, message_from="sender@example.com", message_to=["recipient@example.com"], subject="Encrypted", plain_message="Sent over TLS.", username="sender@example.com", password="secret", ) ``` -------------------------------- ### IMAPClient - Fetch and Folder Operations Source: https://context7.com/seanthegeek/mailsuite/llms.txt Demonstrates fetching messages (both parsed and raw) and performing folder operations like creating, moving, and deleting messages using the IMAPClient. ```APIDOC ## IMAPClient Operations ### Fetching Messages Fetch and parse a single message: ```python msg = client.fetch_message(1001, parse=True) print(msg["subject"]) ``` Fetch raw RFC 822: ```python raw = client.fetch_message(1001, parse=False) ``` ### Folder Operations Create a new folder: ```python client.create_folder("Processed/2024") ``` Move messages to a folder: ```python client.move_messages([1001, 1002], "Processed/2024") ``` Delete messages: ```python client.delete_messages([1003]) ``` ``` -------------------------------- ### Send email with send_email Source: https://context7.com/seanthegeek/mailsuite/llms.txt Connects to an SMTP server, negotiates STARTTLS, authenticates, and sends a message. Supports CC, BCC, custom headers, attachments, and DKIM signing. Raises SMTPError on failure. ```python from mailsuite.smtp import send_email, SMTPError # Plain send with STARTTLS auto-negotiation try: send_email( host="smtp.example.com", message_from="sender@example.com", message_to=["recipient@example.com"], message_cc=["cc@example.com"], subject="Hello", plain_message="Hello, world!", html_message="
Hello, world!
", attachments=[("hello.txt", b"Hello, world!")], username="sender@example.com", password="secret", ) except SMTPError as e: print(f"Send failed: {e}") ``` -------------------------------- ### Lint mail suite code with ruff Source: https://github.com/seanthegeek/mailsuite/blob/master/AGENTS.md Run the ruff linter on the mailsuite and tests directories to check for code style and potential errors. ```bash ruff check mailsuite tests ``` -------------------------------- ### Perform IMAP Folder Operations Source: https://context7.com/seanthegeek/mailsuite/llms.txt Demonstrates creating a new folder, moving messages to a folder, and deleting messages using IMAPClient. ```python client.create_folder("Processed/2024") ``` ```python client.move_messages([1001, 1002], "Processed/2024") ``` ```python client.delete_messages([1003]) ``` -------------------------------- ### Process Mailbox with MailboxConnection Interface Source: https://context7.com/seanthegeek/mailsuite/llms.txt Demonstrates using the abstract `MailboxConnection` interface to process messages in a folder. This code is backend-agnostic and works with any compatible connection. ```python from mailsuite.mailbox import MailboxConnection from mailsuite.utils import parse_email def process_mailbox(conn: MailboxConnection, folder: str) -> None: """Works with any backend: IMAP, MSGraph, Gmail, Maildir.""" conn.create_folder("Done") message_ids = conn.fetch_messages(folder) for mid in message_ids: raw = conn.fetch_message(mid) msg = parse_email(raw) print(msg["subject"], msg["from"]["address"]) conn.move_message(mid, "Done") ``` -------------------------------- ### Run tests with pytest and coverage Source: https://github.com/seanthegeek/mailsuite/blob/master/AGENTS.md Execute the test suite using pytest. Use the --cov flag to generate a code coverage report for the mailsuite package. ```bash pytest pytest --cov=mailsuite ``` -------------------------------- ### create_folder Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Create a new folder or label within the mailbox. ```APIDOC ## create_folder(folder_name: str) -> None ### Description Create a folder/label in the mailbox. ### Parameters #### Path Parameters - **folder_name** (str) - Required - The name of the folder to create. ``` -------------------------------- ### Configure MSGraphConnection for Sovereign Cloud Source: https://github.com/seanthegeek/mailsuite/blob/master/README.md When using MSGraphConnection, you can target a specific sovereign cloud or other Graph endpoints by passing the `graph_url` parameter during initialization. ```python MSGraphConnection(..., graph_url="https://graph.microsoft.com/.us") ``` -------------------------------- ### Send an email using GmailConnection Source: https://context7.com/seanthegeek/mailsuite/llms.txt Construct and send a simple email with specified recipients, subject, and plain text message using the GmailConnection. Returns the sent message ID. ```python # Send a message sent_id = conn.send_message( message_from="me@gmail.com", message_to=["colleague@example.com"], subject="Hello", plain_message="Just a quick note.", ) print(sent_id) # Gmail message ID ``` -------------------------------- ### create_email Source: https://context7.com/seanthegeek/mailsuite/llms.txt Constructs a `MIMEMultipart` message from provided components, including plain-text body, HTML body, and file attachments. Returns a standards-compliant RFC 822 string. ```APIDOC ## create_email ### Description Builds an RFC 822 message string from various components, including sender, recipients, subject, plain-text and HTML bodies, and attachments. The function returns a standards-compliant RFC 822 string suitable for transmission. ### Method `create_email(message_from: str, message_to: list[str], message_cc: list[str] | None = None, subject: str, plain_message: str | None = None, html_message: str | None = None, attachments: list[tuple[str, bytes]] | None = None, message_headers: dict[str, str] | None = None) -> str` ### Parameters #### Arguments - **message_from** (str) - Required - The sender's email address and optionally display name. - **message_to** (list[str]) - Required - A list of recipient email addresses. - **message_cc** (list[str] | None) - Optional - A list of CC recipient email addresses. - **subject** (str) - Required - The subject line of the email. - **plain_message** (str | None) - Optional - The plain-text version of the email body. - **html_message** (str | None) - Optional - The HTML version of the email body. - **attachments** (list[tuple[str, bytes]] | None) - Optional - A list of tuples, where each tuple contains the filename and content (as bytes) of an attachment. - **message_headers** (dict[str, str] | None) - Optional - A dictionary of custom email headers to include. ### Request Example ```python from mailsuite.utils import create_email rfc822 = create_email( message_from="AlicePlease find the report attached.
", attachments=[ ("report.pdf", open("report.pdf", "rb").read()), ("data.csv", open("data.csv", "rb").read()), ], message_headers={"X-Custom-Header": "value"}, ) print(rfc822[:200]) ``` ### Response #### Success Response - **str** - A string containing the complete RFC 822 formatted email. ``` -------------------------------- ### IMAPConnection.create_folder Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Creates a new folder or label within the IMAP mailbox. ```APIDOC ## IMAPConnection.create_folder ### Description Create a folder/label in the mailbox ### Parameters * **folder_name** (str) - The name of the folder to create ### Returns None ``` -------------------------------- ### Generate DKIM DNS TXT Record Source: https://context7.com/seanthegeek/mailsuite/llms.txt Creates a DKIM DNS TXT record value from a public key or private key, selector, and optional domain. Can output a value-only string or a full zone file line. ```python from mailsuite.dkim import generate_dkim_keypair, generate_dkim_txt_record private_pem, public_b64 = generate_dkim_keypair() # Value-only (no domain) record_value = generate_dkim_txt_record(public_b64, selector="mail") print(record_value) # v=DKIM1; k=rsa; p=MIIBIjAN... # Full zone-file line zone_line = generate_dkim_txt_record( public_b64, selector="mail", domain="example.com", flags="y", # testing mode ) print(zone_line) # mail._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; t=y; p=MIIBIjAN..." # Also accepts a PEM private key directly zone_line2 = generate_dkim_txt_record(private_pem, selector="mail", domain="example.com") ``` -------------------------------- ### IMAPClient.create_folder Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Creates an IMAP folder at the specified path. This method is part of the IMAPClient class for managing mail folders. ```APIDOC ## create_folder folder: str ### Description Creates an IMAP folder at the given path. ### Parameters #### Path Parameters - **folder** (str) - Required - The path of the folder to create - **_attempt** (int) - Optional - The attempt number ``` -------------------------------- ### Watch for new Gmail messages with a callback Source: https://context7.com/seanthegeek/mailsuite/llms.txt Set up a polling mechanism to watch the INBOX for new messages. The provided handle function processes new messages and moves them to the 'Done' folder. Checks every 60 seconds. ```python # Watch via polling def handle(connection: GmailConnection): for mid in connection.fetch_messages("INBOX"): raw = connection.fetch_message(mid) msg = parse_email(raw) print("New:", msg["subject"]) connection.move_message(mid, "Done") conn.watch(check_callback=handle, check_timeout=60) ``` -------------------------------- ### IMAPClient - OAuth2 Login Source: https://context7.com/seanthegeek/mailsuite/llms.txt Illustrates how to configure IMAPClient for OAuth2 authentication, providing a token provider function for long-running sessions. ```APIDOC ## IMAPClient OAuth2 Login Configure IMAPClient with a token provider for OAuth2: ```python def get_token(): # Your OAuth2 token-refresh logic here return "ya29.current_access_token" oauth_client = IMAPClient( host="imap.gmail.com", username="user@gmail.com", oauth2_token_provider=get_token, oauth2_mechanism="XOAUTH2", ) ``` ``` -------------------------------- ### query_dns Source: https://context7.com/seanthegeek/mailsuite/llms.txt Resolves DNS records of any type, supporting optional caching and custom nameservers. Returns a list of answer strings. ```APIDOC ## `query_dns` — Query DNS records Resolves DNS records of any type with optional caching and custom nameservers. Returns a list of answer strings. ```python from mailsuite.utils import query_dns from expiringdict import ExpiringDict cache = ExpiringDict(max_len=200, max_age_seconds=300) # Look up MX records mx_records = query_dns("example.com", "MX", cache=cache, timeout=3.0) print(mx_records) # ["10 mail.example.com", "20 mail2.example.com"] # Look up a DKIM TXT record txt = query_dns("selector1._domainkey.example.com", "TXT", nameservers=["8.8.8.8"]) print(txt) # ["v=DKIM1; k=rsa; p=MIIBIjAN..."] ``` ``` -------------------------------- ### Perform reverse DNS lookup with get_reverse_dns Source: https://context7.com/seanthegeek/mailsuite/llms.txt Resolves an IP address to its PTR hostname via a reverse DNS lookup. Returns None if no PTR record exists. Supports a timeout parameter. ```python from mailsuite.utils import get_reverse_dns hostname = get_reverse_dns("8.8.8.8", timeout=3.0) print(hostname) # "dns.google" unknown = get_reverse_dns("192.0.2.1") print(unknown) # None ``` -------------------------------- ### IMAP Client with Auto-Reconnection Source: https://context7.com/seanthegeek/mailsuite/llms.txt A simplified IMAP client that handles STARTTLS, IDLE, automatic reconnection, and namespace normalization. Supports password and OAuth2 authentication with workarounds for common mail servers. ```python from mailsuite.imap import IMAPClient, MaxRetriesExceeded from mailsuite.utils import parse_email # --- Password login --- client = IMAPClient( host="imap.example.com", username="user@example.com", password="secret", port=993, ssl=True, timeout=30, max_retries=4, initial_folder="INBOX", ) # List all messages in INBOX uids = client.search() print(uids) # [1001, 1002, 1003] ``` -------------------------------- ### Query DNS records with query_dns Source: https://context7.com/seanthegeek/mailsuite/llms.txt Resolves DNS records of any type with optional caching and custom nameservers. Returns a list of answer strings. Uses ExpiringDict for caching. ```python from mailsuite.utils import query_dns from expiringdict import ExpiringDict cache = ExpiringDict(max_len=200, max_age_seconds=300) # Look up MX records mx_records = query_dns("example.com", "MX", cache=cache, timeout=3.0) print(mx_records) # ["10 mail.example.com", "20 mail2.example.com"] # Look up a DKIM TXT record txt = query_dns("selector1._domainkey.example.com", "TXT", nameservers=["8.8.8.8"]) print(txt) # ["v=DKIM1; k=rsa; p=MIIBIjAN..."] ``` -------------------------------- ### Type-check mail suite code with pyright Source: https://github.com/seanthegeek/mailsuite/blob/master/AGENTS.md Perform static type checking using pyright, forcing the latest version to ensure consistency with the bundled typeshed. ```bash PYRIGHT_PYTHON_FORCE_VERSION=latest pyright mailsuite ``` -------------------------------- ### Create RFC 822 Email with mailsuite.utils.create_email Source: https://context7.com/seanthegeek/mailsuite/llms.txt Constructs a standards-compliant RFC 822 email string from provided components like sender, recipients, subject, bodies, and attachments. Supports custom headers. ```python from mailsuite.utils import create_email rfc822 = create_email( message_from="AlicePlease find the report attached.
", attachments=[ ("report.pdf", open("report.pdf", "rb").read()), ("data.csv", open("data.csv", "rb").read()), ], message_headers={"X-Custom-Header": "value"}, ) print(rfc822[:200]) ``` -------------------------------- ### OAuth2 Login with IMAPClient Source: https://context7.com/seanthegeek/mailsuite/llms.txt Configures IMAPClient for OAuth2 authentication, suitable for long-running sessions. Requires a token provider function that returns the current access token. ```python def get_token(): # Your OAuth2 token-refresh logic here return "ya29.current_access_token" oauth_client = IMAPClient( host="imap.gmail.com", username="user@gmail.com", oauth2_token_provider=get_token, oauth2_mechanism="XOAUTH2", ) ``` -------------------------------- ### Fetch and process Gmail messages Source: https://context7.com/seanthegeek/mailsuite/llms.txt Iterate through messages in the INBOX, fetch raw content, parse it, and move processed messages. Requires a configured GmailConnection instance. ```python # Fetch and process messages for msg_id in conn.fetch_messages("INBOX"): raw = conn.fetch_message(msg_id) msg = parse_email(raw) print(msg["subject"], msg["from"]["address"]) conn.move_message(msg_id, "Processed") ``` -------------------------------- ### MaildirConnection.create_folder Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Creates a new folder within the Maildir mailbox. ```APIDOC ## MaildirConnection.create_folder ### Description Create a folder/label in the mailbox ### Parameters * **folder_name** (str) - The name of the folder to create ### Returns None ``` -------------------------------- ### IMAPConnection: Fetch and Move Messages Source: https://context7.com/seanthegeek/mailsuite/llms.txt Connects to an IMAP server using `IMAPConnection` and processes all messages in the 'INBOX'. Each message is fetched, parsed, and then moved to the 'Processed' folder. ```python from mailsuite.mailbox import IMAPConnection from mailsuite.utils import parse_email conn = IMAPConnection( host="imap.example.com", user="user@example.com", password="secret", ssl=True, timeout=30, max_retries=4, ) # Fetch and process all messages for uid in conn.fetch_messages("INBOX"): raw = conn.fetch_message(uid) msg = parse_email(raw) print(msg["subject"]) conn.move_message(uid, "Processed") ``` -------------------------------- ### MSGraphConnection: List, Fetch, and Move Messages Source: https://context7.com/seanthegeek/mailsuite/llms.txt Fetches messages from the 'INBOX' using `MSGraphConnection`, marking them as read upon retrieval. Each message is parsed, and then moved to the 'Processed' folder. ```python from mailsuite.mailbox import MSGraphConnection from mailsuite.utils import parse_email # App-only (daemon / service) — ClientSecret flow conn = MSGraphConnection( auth_method="ClientSecret", mailbox="reports@example.com", client_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", client_secret="super_secret_value", username=None, password=None, tenant_id="yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy", token_file="/var/lib/myapp/graph_token.json", allow_unencrypted_storage=False, ) # List and fetch messages for msg_id in conn.fetch_messages("INBOX", batch_size=50): raw = conn.fetch_message(msg_id, mark_read=True) msg = parse_email(raw) print(msg["subject"]) conn.move_message(msg_id, "Processed") ``` -------------------------------- ### Mailbox Connection Interface Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Abstract base class for mailbox connections, providing a provider-agnostic interface for mailbox operations. ```APIDOC ## mailsuite.mailbox.base.MailboxConnection ### Description An abstract base class representing a provider-agnostic interface for a mailbox. Subclasses implement methods for specific protocols like IMAP, Microsoft Graph, Gmail, Maildir, etc. ### Methods #### create_folder(folder_name: str) → None Create a folder/label in the mailbox. #### delete_message(message_id: Any) → None Permanently delete a message by identifier. #### fetch_message(message_id: Any, **kwargs: Any) → str Fetch the raw RFC 822 contents of a message by identifier. #### fetch_messages(reports_folder: str, **kwargs: Any) → list Return a list of message identifiers in the given folder. #### keepalive() → None Send a no-op to keep the connection alive (if applicable). #### move_message(message_id: Any, folder_name: str) → None Move a message to the named folder. ``` -------------------------------- ### IMAP IDLE for New Mail Notifications Source: https://context7.com/seanthegeek/mailsuite/llms.txt Sets up IMAP IDLE to receive push notifications for new messages. The `idle_callback` function is executed when new mail arrives. The client automatically refreshes IDLE. ```python def on_new_mail(imap_client: IMAPClient): uids = imap_client.search() for uid in uids: msg = imap_client.fetch_message(uid, parse=True) print("New message:", msg["subject"]) imap_client.move_messages([uid], "Processed") # Blocks until KeyboardInterrupt; auto-refreshes IDLE every 5 minutes IMAPClient( host="imap.example.com", username="user@example.com", password="secret", idle_callback=on_new_mail, idle_timeout=30, ) ``` -------------------------------- ### IMAPConnection - IMAP Backend Source: https://context7.com/seanthegeek/mailsuite/llms.txt Wraps IMAPClient behind the MailboxConnection interface and adds a `watch` method for IMAP IDLE. Sending mail is not supported directly. ```APIDOC ## `IMAPConnection` - IMAP Backend Wraps `IMAPClient` behind the `MailboxConnection` interface and adds a `watch` method that drives IMAP IDLE. Sending is not supported; use `mailsuite.smtp.send_email` instead. ```python from mailsuite.mailbox import IMAPConnection from mailsuite.utils import parse_email conn = IMAPConnection( host="imap.example.com", user="user@example.com", password="secret", ssl=True, timeout=30, max_retries=4, ) # Fetch and process all messages for uid in conn.fetch_messages("INBOX"): raw = conn.fetch_message(uid) msg = parse_email(raw) print(msg["subject"]) conn.move_message(uid, "Processed") # Watch with IDLE def handle(connection: IMAPConnection): for uid in connection.fetch_messages("INBOX"): raw = connection.fetch_message(uid) msg = parse_email(raw) print("Arrived:", msg["subject"]) connection.move_message(uid, "Done") conn.watch(check_callback=handle, check_timeout=30) ``` ``` -------------------------------- ### Parse Authentication-Results header with parse_authentication_results Source: https://context7.com/seanthegeek/mailsuite/llms.txt Normalizes raw Authentication-Results header strings into a structured dictionary. Handles both single strings and lists of headers. The from_domain parameter is used for validation. ```python from mailsuite.utils import parse_authentication_results raw_header = ( "mx.example.com; " "dkim=pass header.i=@example.com header.s=selector1; " "dmarc=pass header.from=example.com; " "spf=pass smtp.mailfrom=example.com" ) parsed = parse_authentication_results(raw_header, from_domain="example.com") print(parsed["dkim"]["result"]) # "pass" print(parsed["dkim"]["header.d"]) # "example.com" print(parsed["dmarc"]["result"]) # "pass" print(parsed["dmarc"]["header.from"]) # "example.com" print(parsed["spf"]["result"]) # "pass" # List variant — one dict per header results = parse_authentication_results( ["server1; dkim=pass header.d=a.com", "server2; dmarc=pass header.from=a.com"], from_domain="a.com", ) ``` -------------------------------- ### Create Folder in MS Graph Mailbox Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Create a new folder or label within a Microsoft Graph-backed mailbox. ```python create_folder(folder_name: str) → None ``` -------------------------------- ### send_email Source: https://context7.com/seanthegeek/mailsuite/llms.txt Sends an email via an SMTP relay, supporting STARTTLS, authentication, CC, BCC, custom headers, attachments, and optional DKIM signing. Raises `SMTPError` on failure. ```APIDOC ## `send_email` — Send an email via an SMTP relay Connects to an SMTP server, negotiates STARTTLS automatically when available, authenticates with optional credentials, and sends the message. Supports CC, BCC, custom headers, attachments, and optional DKIM signing. Raises `SMTPError` (a `RuntimeError` subclass) on any transport failure. ```python from mailsuite.smtp import send_email, SMTPError # Plain send with STARTTLS auto-negotiation try: send_email( host="smtp.example.com", message_from="sender@example.com", message_to=["recipient@example.com"], message_cc=["cc@example.com"], subject="Hello", plain_message="Hello, world!", html_message="Hello, world!
", attachments=[("hello.txt", b"Hello, world!")], username="sender@example.com", password="secret", ) except SMTPError as e: print(f"Send failed: {e}") ``` ``` -------------------------------- ### get_reverse_dns Source: https://context7.com/seanthegeek/mailsuite/llms.txt Performs a reverse DNS lookup to resolve an IP address to its PTR hostname. Returns `None` if no PTR record is found. ```APIDOC ## `get_reverse_dns` — Reverse DNS lookup Resolves an IP address to its PTR hostname via a reverse DNS lookup. Returns `None` if no PTR record exists. ```python from mailsuite.utils import get_reverse_dns hostname = get_reverse_dns("8.8.8.8", timeout=3.0) print(hostname) # "dns.google" unknown = get_reverse_dns("192.0.2.1") print(unknown) # None ``` ``` -------------------------------- ### Send Email with DKIM Signing Source: https://context7.com/seanthegeek/mailsuite/llms.txt Send emails with DKIM signing enabled by providing a private key and selector. The domain defaults to the sender's domain if not specified. ```python private_key_pem = open("dkim_private.pem").read() send_email( host="smtp.example.com", message_from="sender@example.com", message_to=["recipient@example.com"], subject="DKIM-signed message", plain_message="Signed and delivered.", username="sender@example.com", password="secret", dkim_private_key=private_key_pem, dkim_selector="selector1", # dkim_domain defaults to the domain of message_from ) ``` -------------------------------- ### verify_email Source: https://context7.com/seanthegeek/mailsuite/llms.txt Verifies DKIM signatures on a received email message by performing live DNS lookups. ```APIDOC ## verify_email ### Description Verifies all `DKIM-Signature` headers present in a received email message. This function performs live DNS lookups to validate the signatures. It returns a dictionary indicating the overall validity and details for each signature. ### Parameters - **raw** (string) - Required - The raw content of the received email. - **timeout** (float) - Optional - The timeout in seconds for DNS lookups. Defaults to 5.0. - **minkey** (integer) - Optional - The minimum key size in bits for verification. Defaults to 1024. ### Returns A dictionary with a top-level `valid` key (boolean) and a `signatures` list. Each item in the `signatures` list is a dictionary containing `domain`, `selector`, `valid` (boolean), and `error` (string or None). ### Request Example ```python from mailsuite.dkim import verify_email raw = open("received.eml").read() result = verify_email(raw, timeout=5.0, minkey=1024) print(result["valid"]) # True if at least one signature verified for sig in result["signatures"]: print(sig["domain"]) print(sig["selector"]) print(sig["valid"]) print(sig["error"]) ``` ``` -------------------------------- ### fetch_messages Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Obtain a list of message identifiers within a specified folder. ```APIDOC ## fetch_messages(reports_folder: str, **kwargs: Any) -> list ### Description Return a list of message identifiers in the given folder. ### Parameters #### Path Parameters - **reports_folder** (str) - Required - The name of the folder to fetch messages from. #### Query Parameters - **kwargs** (Any) - Optional - Additional keyword arguments for fetching. ``` -------------------------------- ### Verify email sender domain with from_trusted_domain Source: https://context7.com/seanthegeek/mailsuite/llms.txt Checks the Authentication-Results header to verify if an email originated from a trusted domain. Only call this on messages received by your own mail infrastructure; the function does not independently verify header authenticity. Set use_authentication_results_original to True for Proofpoint/IronPort gateways. ```python from mailsuite.utils import from_trusted_domain, parse_email raw = open("inbound.eml").read() # Quick call with a raw message string trusted = from_trusted_domain( message=raw, trusted_domains=["example.com", "subsidiary.example.com"], include_sld=True, # also match on SLD use_authentication_results_original=False, # set True for Proofpoint/IronPort gateways ) print(trusted) # True or False # Re-use an already-parsed dict to avoid double-parsing parsed = parse_email(raw) trusted = from_trusted_domain(parsed, trusted_domains=["example.com"]) print(trusted) # True ``` -------------------------------- ### IMAPClient Source: https://context7.com/seanthegeek/mailsuite/llms.txt A simplified, auto-reconnecting IMAP client that enhances the standard `imapclient.IMAPClient` with features like STARTTLS, IDLE, automatic reconnection, and support for various authentication methods. ```APIDOC ## IMAPClient ### Description A subclass of `imapclient.IMAPClient` designed for ease of use and robustness. It automatically handles STARTTLS negotiation, IMAP IDLE, and reconnection on network issues. It also includes workarounds for common mail server quirks and supports both password and OAuth2 authentication. ### Parameters - **host** (string) - Required - The IMAP server hostname. - **username** (string) - Required - The username for authentication. - **password** (string) - Optional - The password for password-based authentication. - **port** (integer) - Optional - The IMAP server port. Defaults to 993 if `ssl` is true, otherwise 143. - **ssl** (boolean) - Optional - Whether to use SSL/TLS for the connection. Defaults to true. - **timeout** (integer) - Optional - The connection timeout in seconds. Defaults to 30. - **max_retries** (integer) - Optional - The maximum number of reconnection attempts. Defaults to 4. - **initial_folder** (string) - Optional - The folder to select after connecting. Defaults to "INBOX". ### Request Example (Password login) ```python from mailsuite.imap import IMAPClient, MaxRetriesExceeded from mailsuite.utils import parse_email client = IMAPClient( host="imap.example.com", username="user@example.com", password="secret", port=993, ssl=True, timeout=30, max_retries=4, initial_folder="INBOX", ) # List all messages in INBOX uids = client.search() print(uids) # [1001, 1002, 1003] ``` ``` -------------------------------- ### create_email Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Creates an RFC 822 email message and returns it as a string. Supports various email components like recipients, subject, headers, attachments, and message bodies. ```APIDOC ## mailsuite.utils.create_email ### Description Creates an RFC 822 email message and returns it as a string. ### Parameters * **message_from** (str) - The value of the message from header * **message_to** (list[str] | None) - A list of addresses to send mail to * **message_cc** (list[str] | None) - A List of addresses to Carbon Copy (CC) * **subject** (str | None) - The message subject * **message_headers** (dict | None) - Custom message headers * **attachments** (list[tuple[str, bytes]] | None) - A list of tuples, containing a filename and bytes * **plain_message** (str | None) - The plain text message body * **html_message** (str | None) - The HTML message body ### Returns str - A RFC 822 email message ``` -------------------------------- ### Send Message Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Send a message using the mailbox's native send API. Backends without native support will raise NotImplementedError. Use mailsuite.smtp.send_email() for direct sending. ```python send_message(*args: Any, **kwargs: Any) → str | None ``` -------------------------------- ### watch Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Poll the mailbox at `check_timeout`-second intervals. ```APIDOC ## watch(check_callback: Callable[[MailboxConnection], None], check_timeout: int, config_reloading: Callable[[], bool] | None = None) -> None ### Description Poll the mailbox at `check_timeout`-second intervals. ### Parameters * **check_callback** (Callable[[MailboxConnection], None]) - A callback function that will be called with the mailbox connection. * **check_timeout** (int) - The interval in seconds to poll the mailbox. * **config_reloading** (Callable[[], bool] | None) - An optional callback function to check for configuration reloads. ``` -------------------------------- ### Generate DKIM Keypair Source: https://context7.com/seanthegeek/mailsuite/llms.txt Generates a new RSA DKIM keypair. The private key is PEM-encoded, and the public key is base64-encoded for DNS TXT records. Persist the private key for signing emails. ```python from mailsuite.dkim import generate_dkim_keypair private_pem, public_b64 = generate_dkim_keypair(key_size=2048) # Persist the private key with open("dkim_private.pem", "w") as f: f.write(private_pem) print(public_b64[:40]) # "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCg..." ``` -------------------------------- ### DKIM Generate TXT Record Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Generates a DKIM TXT record suitable for DNS configuration. It can optionally include the full DNS owner name if a domain is provided. ```APIDOC ## mailsuite.dkim.generate_dkim_txt_record ### Description Generates a DKIM TXT record. If a domain is provided, the full DNS owner name is included. ### Parameters * **public_key** (str | bytes) - Required - A base64-encoded public key, or a PEM-encoded private or public key. * **selector** (str) - Optional, defaults to 'default' - The DKIM selector. * **domain** (str | None) - Optional - The domain for which the DKIM record is generated. If provided, the output includes the full DNS owner name. * **flags** (str | None) - Optional - An optional value for the `t=` flags tag (e.g., "y" for testing mode). * **note** (str | None) - Optional - An optional value for the `n=` notes tag. ### Returns * **str** - The full DNS record (owner name, class, type, and quoted value) as a single line if `domain` is given, otherwise just the record value. ``` -------------------------------- ### get_reverse_dns Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Resolves an IP address to a hostname using a reverse DNS query. Supports optional caching, custom nameservers, and timeout settings. ```APIDOC ## mailsuite.utils.get_reverse_dns ### Description Resolves an IP address to a hostname using a reverse DNS query. ### Parameters * **ip_address** (str) - The IP address to resolve * **cache** (ExpiringDict | None, optional) - Cache storage * **nameservers** (list[str] | None, optional) - A list of one or more nameservers to use * **timeout** (float | int, optional) - Sets the DNS query timeout in seconds. Defaults to 2.0. ### Returns str | None - The reverse DNS hostname (if any) ``` -------------------------------- ### decode_base64 Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Decodes a base64 encoded string, with optional padding. Returns the decoded bytes. ```APIDOC ## mailsuite.utils.decode_base64 ### Description Decodes a base64 string, with padding being optional. ### Parameters * **data** (str) - A base64 encoded string ### Returns bytes - The decoded bytes ``` -------------------------------- ### Keep Connection Alive Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Send a no-operation command to maintain an active connection. ```python keepalive() → None ``` -------------------------------- ### send_email Source: https://context7.com/seanthegeek/mailsuite/llms.txt Sends an email using the specified SMTP server. Supports explicit TLS and DKIM signing. ```APIDOC ## send_email ### Description Sends an email using the specified SMTP server. This function can be configured to use explicit TLS for secure transmission and can optionally sign the email with DKIM. ### Parameters - **host** (string) - Required - The SMTP server hostname. - **port** (integer) - Optional - The SMTP server port. Defaults to 587 if not specified. - **require_encryption** (boolean) - Optional - If true, requires TLS encryption. Defaults to false. - **message_from** (string) - Required - The sender's email address. - **message_to** (list of strings) - Required - A list of recipient email addresses. - **subject** (string) - Required - The subject of the email. - **plain_message** (string) - Required - The plain text content of the email. - **username** (string) - Optional - The username for SMTP authentication. - **password** (string) - Optional - The password for SMTP authentication. - **dkim_private_key** (string) - Optional - The PEM-encoded private key for DKIM signing. - **dkim_selector** (string) - Optional - The DKIM selector. - **dkim_domain** (string) - Optional - The DKIM domain. Defaults to the domain of `message_from`. ### Request Example (Explicit TLS) ```python send_email( host="smtp.example.com", port=465, require_encryption=True, message_from="sender@example.com", message_to=["recipient@example.com"], subject="Encrypted", plain_message="Sent over TLS.", username="sender@example.com", password="secret", ) ``` ### Request Example (DKIM Signing) ```python private_key_pem = open("dkim_private.pem").read() send_email( host="smtp.example.com", message_from="sender@example.com", message_to=["recipient@example.com"], subject="DKIM-signed message", plain_message="Signed and delivered.", username="sender@example.com", password="secret", dkim_private_key=private_key_pem, dkim_selector="selector1", ) ``` ``` -------------------------------- ### generate_dkim_keypair Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Generates a new DKIM RSA keypair, returning both the private and public keys. ```APIDOC ## generate_dkim_keypair(key_size: int = 2048) -> Tuple[str, str] ### Description Generates a DKIM RSA keypair. ### Parameters #### Path Parameters - **key_size** (int) - Optional - The RSA key size in bits (1024 minimum, 2048 recommended) ### Returns - A tuple of `(private_key_pem, public_key_b64)` ``` -------------------------------- ### watch Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Monitor the mailbox for new messages and trigger a callback function upon arrival or at specified intervals. ```APIDOC ## watch(check_callback: Callable[[MailboxConnection], None], check_timeout: int, config_reloading: Callable[[], bool] | None = None) -> None ### Description Watch the mailbox for new messages, invoking `check_callback` when new mail arrives or on a polling interval. ### Parameters #### Path Parameters - **check_callback** (Callable[[MailboxConnection], None]) - Required - Called with this `MailboxConnection` instance whenever the watcher fires. - **check_timeout** (int) - Required - Polling interval (or IDLE timeout) in seconds. - **config_reloading** (Callable[[], bool] | None) - Optional - Optional zero-argument callable. When it returns a truthy value, the watcher exits cleanly so the caller can reload configuration. ``` -------------------------------- ### generate_dkim_txt_record Source: https://context7.com/seanthegeek/mailsuite/llms.txt Generates a DKIM DNS TXT record value from a public key, selector, and optional domain. ```APIDOC ## generate_dkim_txt_record ### Description Generates the value for a DKIM DNS TXT record. It accepts a public key (either base64 string or PEM format) along with a selector and an optional domain. If the domain is provided, the output includes the full owner name for direct use in zone files. ### Parameters - **public_key** (string) - Required - The base64-encoded public key or PEM-encoded private key. - **selector** (string) - Required - The DKIM selector. - **domain** (string) - Optional - The domain name for which the DKIM record is generated. If provided, the full owner name is included. - **flags** (string) - Optional - Flags for the DKIM record, e.g., 'y' for testing mode. ### Returns A string representing the DKIM DNS TXT record value. ### Request Example (Value-only) ```python from mailsuite.dkim import generate_dkim_keypair, generate_dkim_txt_record private_pem, public_b64 = generate_dkim_keypair() record_value = generate_dkim_txt_record(public_b64, selector="mail") print(record_value) # v=DKIM1; k=rsa; p=MIIBIjAN... ``` ### Request Example (Full zone-file line) ```python zone_line = generate_dkim_txt_record( public_b64, selector="mail", domain="example.com", flags="y", # testing mode ) print(zone_line) # mail._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; t=y; p=MIIBIjAN..." # Also accepts a PEM private key directly zone_line2 = generate_dkim_txt_record(private_pem, selector="mail", domain="example.com") ``` ``` -------------------------------- ### Watch for New Messages Source: https://github.com/seanthegeek/mailsuite/blob/master/docs/api.md Monitor the mailbox for new messages and trigger a callback function upon arrival or at specified intervals. Optionally, a configuration reloading check can be performed. ```python watch(check_callback: Callable[[MailboxConnection], None], check_timeout: int, config_reloading: Callable[[], bool] | None = None) → None ```