|
# retoor <retoor@molodetz.nl>
|
|
|
|
from __future__ import annotations
|
|
|
|
from .spec import Action, Param
|
|
|
|
REMOTE_NOTE = (
|
|
"This reaches the user's OWN external mailbox over IMAP/SMTP, not this platform. The "
|
|
"account must be configured first with email_account_set."
|
|
)
|
|
|
|
|
|
def arg(
|
|
name: str, description: str, required: bool = False, kind: str = "string"
|
|
) -> Param:
|
|
return Param(
|
|
name=name,
|
|
location="body",
|
|
description=description,
|
|
required=required,
|
|
type=kind,
|
|
)
|
|
|
|
|
|
ACCOUNT = arg(
|
|
"account",
|
|
"The label of the configured email account to use (see email_accounts_list).",
|
|
required=True,
|
|
)
|
|
FOLDER = arg("folder", "Mailbox folder; defaults to INBOX when omitted.")
|
|
UID = arg("uid", "The message UID returned by email_list_messages / email_search.", required=True)
|
|
FILTERS = (
|
|
arg("unseen", "Only unread messages.", kind="boolean"),
|
|
arg("seen", "Only read messages.", kind="boolean"),
|
|
arg("flagged", "Only flagged messages.", kind="boolean"),
|
|
arg("from", "Match the sender address or name."),
|
|
arg("subject", "Match text in the subject."),
|
|
arg("since", "Only messages on or after this date, formatted DD-Mon-YYYY (e.g. 01-Jan-2026)."),
|
|
arg("text", "Match text anywhere in the message."),
|
|
)
|
|
|
|
EMAIL_ACTIONS: tuple[Action, ...] = (
|
|
Action(
|
|
name="email_accounts_list",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="List the user's configured email accounts (passwords are never returned)",
|
|
description="Returns each saved account's connection settings without the password.",
|
|
handler="email",
|
|
requires_auth=True,
|
|
read_only=True,
|
|
),
|
|
Action(
|
|
name="email_account_get",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Read one configured email account's connection settings",
|
|
description="Returns the account settings without the password (password_set indicates whether one is stored).",
|
|
handler="email",
|
|
requires_auth=True,
|
|
read_only=True,
|
|
params=(ACCOUNT,),
|
|
),
|
|
Action(
|
|
name="email_account_set",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Create or update an email account connection (IMAP + SMTP)",
|
|
description=(
|
|
"Saves an IMAP/SMTP connection under a label. Sensible defaults are applied when a "
|
|
"field is omitted: imap_port 993 with imap_ssl on, smtp_port 587 with smtp_starttls on, "
|
|
"from_address falls back to username. Provide host, username and password at minimum. "
|
|
+ REMOTE_NOTE
|
|
),
|
|
handler="email",
|
|
requires_auth=True,
|
|
params=(
|
|
ACCOUNT,
|
|
arg("imap_host", "IMAP server hostname (e.g. imap.gmail.com)."),
|
|
arg("imap_port", "IMAP port (default 993).", kind="integer"),
|
|
arg("imap_ssl", "Use implicit SSL/TLS for IMAP (default true).", kind="boolean"),
|
|
arg("imap_starttls", "Upgrade a plain IMAP connection with STARTTLS (default false).", kind="boolean"),
|
|
arg("smtp_host", "SMTP server hostname (e.g. smtp.gmail.com)."),
|
|
arg("smtp_port", "SMTP port (default 587).", kind="integer"),
|
|
arg("smtp_ssl", "Use implicit SSL/TLS for SMTP (default false; set true for port 465).", kind="boolean"),
|
|
arg("smtp_starttls", "Upgrade a plain SMTP connection with STARTTLS (default true).", kind="boolean"),
|
|
arg("username", "Login username (usually the full email address)."),
|
|
arg("password", "Login password or app-specific password."),
|
|
arg("from_address", "From address for sent mail (defaults to the username)."),
|
|
arg("from_name", "Display name for sent mail."),
|
|
),
|
|
),
|
|
Action(
|
|
name="email_account_delete",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Delete a saved email account connection (confirmation required)",
|
|
description="Removes the stored connection. Does not touch the remote mailbox.",
|
|
handler="email",
|
|
requires_auth=True,
|
|
params=(
|
|
ACCOUNT,
|
|
arg(
|
|
"confirm",
|
|
"Set to true only after the user has confirmed the deletion.",
|
|
required=True,
|
|
kind="boolean",
|
|
),
|
|
),
|
|
),
|
|
Action(
|
|
name="email_list_folders",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="List the mailbox folders on the account",
|
|
description=REMOTE_NOTE,
|
|
handler="email",
|
|
requires_auth=True,
|
|
read_only=True,
|
|
params=(ACCOUNT,),
|
|
),
|
|
Action(
|
|
name="email_list_messages",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="List messages in a folder, newest first, with optional filters",
|
|
description=(
|
|
"Returns message summaries (uid, from, subject, date, flags). Use the filters to narrow "
|
|
"the set and limit/offset to page. " + REMOTE_NOTE
|
|
),
|
|
handler="email",
|
|
requires_auth=True,
|
|
read_only=True,
|
|
params=(
|
|
ACCOUNT,
|
|
FOLDER,
|
|
*FILTERS,
|
|
arg("limit", "Maximum messages to return (1-100, default 25).", kind="integer"),
|
|
arg("offset", "Number of messages to skip for paging (default 0).", kind="integer"),
|
|
),
|
|
),
|
|
Action(
|
|
name="email_read_message",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Read the full body, headers and attachment list of one message",
|
|
description="Fetches the decoded text/html body and attachment metadata. " + REMOTE_NOTE,
|
|
handler="email",
|
|
requires_auth=True,
|
|
read_only=True,
|
|
params=(ACCOUNT, FOLDER, UID),
|
|
),
|
|
Action(
|
|
name="email_search",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Search a folder by sender, subject, date, text or read/flag state",
|
|
description="Returns matching message summaries. " + REMOTE_NOTE,
|
|
handler="email",
|
|
requires_auth=True,
|
|
read_only=True,
|
|
params=(
|
|
ACCOUNT,
|
|
FOLDER,
|
|
*FILTERS,
|
|
arg("limit", "Maximum messages to return (1-100, default 25).", kind="integer"),
|
|
),
|
|
),
|
|
Action(
|
|
name="email_mark",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Mark a message read, unread, flagged or unflagged",
|
|
description="Convenience wrapper over the IMAP \\Seen and \\Flagged flags. " + REMOTE_NOTE,
|
|
handler="email",
|
|
requires_auth=True,
|
|
params=(
|
|
ACCOUNT,
|
|
FOLDER,
|
|
UID,
|
|
arg("state", "One of: read, unread, flagged, unflagged.", required=True),
|
|
),
|
|
),
|
|
Action(
|
|
name="email_set_flags",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Add or remove arbitrary IMAP flags on a message",
|
|
description="For advanced use; prefer email_mark for read/flagged. " + REMOTE_NOTE,
|
|
handler="email",
|
|
requires_auth=True,
|
|
params=(
|
|
ACCOUNT,
|
|
FOLDER,
|
|
UID,
|
|
arg("flags", "Comma-separated IMAP flags (e.g. \\Seen, \\Flagged, \\Answered).", required=True),
|
|
arg("add", "true to add the flags, false to remove them (default true).", kind="boolean"),
|
|
),
|
|
),
|
|
Action(
|
|
name="email_move_message",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Move a message to another folder",
|
|
description="Copies the message to the destination folder and removes it from the source. " + REMOTE_NOTE,
|
|
handler="email",
|
|
requires_auth=True,
|
|
params=(
|
|
ACCOUNT,
|
|
FOLDER,
|
|
UID,
|
|
arg("destination", "Destination folder name.", required=True),
|
|
),
|
|
),
|
|
Action(
|
|
name="email_delete_message",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Delete a message (confirmation required)",
|
|
description=(
|
|
"Deletes the message. If 'trash' is given the message is moved there; otherwise it is "
|
|
"flagged \\Deleted and expunged. " + REMOTE_NOTE
|
|
),
|
|
handler="email",
|
|
requires_auth=True,
|
|
params=(
|
|
ACCOUNT,
|
|
FOLDER,
|
|
UID,
|
|
arg("trash", "Optional Trash folder to move the message into instead of expunging."),
|
|
arg(
|
|
"confirm",
|
|
"Set to true only after the user has confirmed the deletion.",
|
|
required=True,
|
|
kind="boolean",
|
|
),
|
|
),
|
|
),
|
|
Action(
|
|
name="email_send",
|
|
method="LOCAL",
|
|
path="",
|
|
summary="Send an email via the account's SMTP server",
|
|
description="Composes and sends a message. " + REMOTE_NOTE,
|
|
handler="email",
|
|
requires_auth=True,
|
|
params=(
|
|
ACCOUNT,
|
|
arg("to", "Recipient address or comma-separated list.", required=True),
|
|
arg("subject", "Email subject."),
|
|
arg("body", "Plain-text body."),
|
|
arg("cc", "CC recipients (comma-separated)."),
|
|
arg("bcc", "BCC recipients (comma-separated)."),
|
|
arg("html", "Optional HTML alternative body."),
|
|
arg("in_reply_to", "Optional Message-ID this email replies to."),
|
|
),
|
|
),
|
|
)
|