Revise contacts and email tools
All checks were successful
Build And Test / publish (push) Successful in 48s

This commit is contained in:
2026-01-01 15:46:44 -08:00
parent 767f076048
commit 5a9ef0e48f
8 changed files with 189 additions and 176 deletions

View File

@@ -153,7 +153,7 @@ def register_email_tools(mcp: FastMCP, service: EmailService):
result = service.delete_draft(email_id, mailbox, permanent)
return result.model_dump()
@mcp.tool(description="Save a new draft email to the Drafts mailbox.")
@mcp.tool(description="Save a new draft email to the Drafts mailbox. Supports reply threading via in_reply_to_email_id.")
@log_tool_call
def save_draft(
to: Optional[list[str]] = None,
@@ -161,27 +161,23 @@ def register_email_tools(mcp: FastMCP, service: EmailService):
body: Optional[str] = None,
cc: Optional[list[str]] = None,
bcc: Optional[list[str]] = None,
reply_to: Optional[str] = None,
html_body: Optional[str] = None,
mailbox: Optional[str] = None,
reply_to_email_id: Optional[str] = None,
reply_mailbox: Optional[str] = None,
in_reply_to_email_id: Optional[str] = None,
in_reply_to_mailbox: Optional[str] = None,
reply_all: bool = False,
) -> dict:
"""
Save a new email draft.
Args:
to: List of recipient email addresses (required unless reply_to_email_id is set)
subject: Email subject line (required unless reply_to_email_id is set)
body: Plain text email body (required unless reply_to_email_id is set)
to: List of recipient email addresses (required unless in_reply_to_email_id is set)
subject: Email subject line (required unless in_reply_to_email_id is set)
body: Plain text email body (required unless in_reply_to_email_id is set)
cc: List of CC recipients (optional)
bcc: List of BCC recipients (optional)
reply_to: Reply-to address (optional)
html_body: HTML version of the email body (optional)
mailbox: Drafts mailbox/folder override (default: auto-detect)
reply_to_email_id: Email ID to reply to (optional)
reply_mailbox: Mailbox containing the reply_to_email_id (default: INBOX)
in_reply_to_email_id: Email UID to reply to (optional, derives recipients/subject and sets threading headers)
in_reply_to_mailbox: Mailbox containing the in_reply_to_email_id (default: INBOX)
reply_all: Whether to include original recipients when replying (default: False)
"""
result = service.save_draft(
@@ -190,16 +186,14 @@ def register_email_tools(mcp: FastMCP, service: EmailService):
body,
cc,
bcc,
reply_to,
html_body,
mailbox,
reply_to_email_id,
reply_mailbox,
in_reply_to_email_id,
in_reply_to_mailbox,
reply_all,
)
return result.model_dump()
@mcp.tool(description="Edit an existing draft email. Only provided fields will be modified.")
@mcp.tool(description="Edit an existing draft email. Only provided fields will be modified. Supports reply threading via in_reply_to_email_id.")
@log_tool_call
def edit_draft(
email_id: str,
@@ -209,10 +203,8 @@ def register_email_tools(mcp: FastMCP, service: EmailService):
body: Optional[str] = None,
cc: Optional[list[str]] = None,
bcc: Optional[list[str]] = None,
reply_to: Optional[str] = None,
html_body: Optional[str] = None,
reply_to_email_id: Optional[str] = None,
reply_mailbox: Optional[str] = None,
in_reply_to_email_id: Optional[str] = None,
in_reply_to_mailbox: Optional[str] = None,
reply_all: bool = False,
) -> dict:
"""
@@ -226,10 +218,8 @@ def register_email_tools(mcp: FastMCP, service: EmailService):
body: Plain text email body
cc: List of CC recipients (optional)
bcc: List of BCC recipients (optional)
reply_to: Reply-to address (optional)
html_body: HTML version of the email body (optional)
reply_to_email_id: Email ID to reply to (optional)
reply_mailbox: Mailbox containing the reply_to_email_id (default: INBOX)
in_reply_to_email_id: Email UID to reply to (optional, derives recipients/subject and sets threading headers)
in_reply_to_mailbox: Mailbox containing the in_reply_to_email_id (default: INBOX)
reply_all: Whether to include original recipients when replying (default: False)
"""
result = service.update_draft(
@@ -240,63 +230,26 @@ def register_email_tools(mcp: FastMCP, service: EmailService):
body,
cc,
bcc,
reply_to,
html_body,
reply_to_email_id,
reply_mailbox,
in_reply_to_email_id,
in_reply_to_mailbox,
reply_all,
)
return result.model_dump()
@mcp.tool(description="Send a new email via SMTP. Supports plain text and HTML content, CC, BCC, reply-to, and custom sender.")
@mcp.tool(description="Send an existing draft by ID. Only drafts can be sent.")
@log_tool_call
async def send_email(
to: Optional[list[str]] = None,
subject: Optional[str] = None,
body: Optional[str] = None,
cc: Optional[list[str]] = None,
bcc: Optional[list[str]] = None,
reply_to: Optional[str] = None,
html_body: Optional[str] = None,
sender_email: Optional[str] = None,
sender_name: Optional[str] = None,
reply_to_email_id: Optional[str] = None,
reply_mailbox: Optional[str] = None,
reply_all: bool = False,
async def send_draft(
email_id: str,
mailbox: Optional[str] = None,
) -> dict:
"""
Send a new email.
Send a draft email.
Args:
to: List of recipient email addresses (required unless reply_to_email_id is set)
subject: Email subject line (required unless reply_to_email_id is set)
body: Plain text email body (required unless reply_to_email_id is set)
cc: List of CC recipients (optional)
bcc: List of BCC recipients (optional)
reply_to: Reply-to address (optional)
html_body: HTML version of the email body (optional)
sender_email: Sender email address (optional, defaults to SMTP_FROM_EMAIL)
sender_name: Sender display name (optional, defaults to SMTP_FROM_NAME)
reply_to_email_id: Email ID to reply to (optional)
reply_mailbox: Mailbox containing the reply_to_email_id (default: INBOX)
reply_all: Whether to include original recipients when replying (default: False)
email_id: The unique ID of the draft to send
mailbox: Drafts mailbox/folder override (default: auto-detect)
"""
result = await service.send_email(
to,
subject,
body,
cc,
bcc,
reply_to,
html_body,
sender_email,
sender_name,
None,
None,
reply_to_email_id,
reply_mailbox,
reply_all,
)
result = await service.send_draft(email_id, mailbox)
return result.model_dump()
@mcp.tool(description="Set or remove IMAP flags on an email. Standard flags: \\Seen, \\Answered, \\Flagged, \\Deleted, \\Draft. Custom keywords are also supported.")
@@ -321,7 +274,7 @@ def register_email_tools(mcp: FastMCP, service: EmailService):
@mcp.tool(description="Unsubscribe from a mailing list. Parses List-Unsubscribe headers and attempts automatic unsubscribe via HTTP or provides mailto instructions.")
@log_tool_call
async def unsubscribe_email(
async def unsubscribe_maillist(
email_id: str,
mailbox: str = "INBOX",
) -> dict: