Skip to content

feat(api): Add SMTP over HTTP REST API endpoint#6989

Closed
tayyebi wants to merge 7 commits intomailcow:stagingfrom
tayyebi:feature/smtp-api
Closed

feat(api): Add SMTP over HTTP REST API endpoint#6989
tayyebi wants to merge 7 commits intomailcow:stagingfrom
tayyebi:feature/smtp-api

Conversation

@tayyebi
Copy link

@tayyebi tayyebi commented Jan 1, 2026

Contribution Guidelines

What does this PR include?

Short Description

Adds a new REST API endpoint POST /api/v1/send/email that allows mailbox users to send emails programmatically via SMTP through HTTP requests.

Key Features:

  • Send emails with plain text and/or HTML body
  • Support for multiple recipients (To, CC, BCC)
  • Reply-to address support
  • Base64 encoded file attachments
  • Mailbox-level authentication required (smtp_user + password)
  • Sender authorization enforced (same rules as SMTP: own mailbox, aliases, sender ACL)

Request Parameters:

Field Type Required Description
from string Yes Sender email address
to array Yes Array of recipient email addresses
subject string Yes Email subject
body string Yes Plain text email body
smtp_user string Yes SMTP username (mailbox login)
password string Yes SMTP password (mailbox login)
html_body string No HTML email body
cc array No CC email addresses
bcc array No BCC email addresses
reply_to string No Reply-to email address
attachments array No Base64 encoded attachments
smtp_host string No SMTP server (default: postfix-mailcow)
smtp_port integer No SMTP port (default: 587)

Example:

curl -X POST 'https://mail.example.com/api/v1/send/email' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: YOUR-API-KEY' \
  -d '{"from":"user@example.com","to":["recipient@example.com"],"subject":"Test","body":"Hello","smtp_user":"user@example.com","password":"mailbox-password"}'

Affected Containers

  • php-fpm-mailcow

Did you run tests?

What did you tested?

  • Sending basic emails with authentication
  • Sending HTML emails with CC/BCC
  • Attachments (base64 encoded)
  • Sender authorization (own mailbox, aliases, sender ACL)
  • Error handling for invalid addresses, missing fields
  • Unauthorized sender rejection

What were the final results? (Awaited, got)

All test cases passed. Emails are sent correctly when mailbox credentials are provided and sender is authorized. Unauthorized senders receive appropriate error messages.

Related

@milkmaker
Copy link
Collaborator

Thanks for contributing!

I noticed that you didn't select staging as your base branch. Please change the base branch to staging.
See the attached picture on how to change the base branch to staging:

check_prs_if_on_staging.png

@tayyebi tayyebi changed the base branch from master to staging January 1, 2026 11:58
@tayyebi tayyebi force-pushed the feature/smtp-api branch 2 times, most recently from 8bf6c1e to ab42876 Compare January 1, 2026 12:11
@dragoangel
Copy link
Collaborator

How this going to work with current API when API key is only used for administrative automation and not even generated per domain. This is wrong by design.

Adds a new API endpoint POST /api/v1/send/email for sending emails
programmatically via SMTP.

Features:
- Send emails with plain text and/or HTML body
- Support for CC, BCC, and reply-to addresses
- Base64 encoded file attachments
- Configurable SMTP host, port, and authentication
- Full validation of email addresses
- Proper error handling with descriptive messages

Files changed:
- data/web/inc/functions.inc.php: Added smtp_api() function
- data/web/json_api.php: Added 'send' action handler
- data/web/api/openapi.yaml: Added endpoint documentation
- data/web/lang/lang.en-gb.json: Added error/success messages
- Remove 400 response (use 200 with error type like other endpoints)
- Add 'danger' to type enum for consistency
- Add 'log' field to response schema
- Update description (auth required)
@tayyebi
Copy link
Author

tayyebi commented Jan 2, 2026

i was trying to keep the code self-describing. and also i have updated the openapi as well to let users know that they can (and mailcow prefers them) to use app_password instead of their mailbox password. 299a815

-      $smtp_pass = isset($data['password']) ? $data['password'] : '';
+      $smtp_pass = $data['app_password'] ?? $data['password'] ?? '';

@tayyebi tayyebi closed this by deleting the head repository Jan 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants