ses-email-notification
Stdio MCP server exposing a single send_email tool backed by AWS SES (SESv2 API).
Credentials come from boto3's default chain: the EC2 instance role in production,
AWS_PROFILE for local testing. No credential configuration in code.
Tool: send_email
| Parameter | Type | Required | Notes |
|---|---|---|---|
to |
list[str] | yes | one or more recipients |
subject |
str | yes | |
body_text |
str | no* | plain-text body |
body_html |
str | no* | HTML body; both → multipart/alternative |
cc |
list[str] | no | |
attachment_paths |
list[str] | no | local file paths inside ATTACHMENT_BASE_DIR |
*At least one of body_text / body_html is required.
Returns the SES MessageId on success. SES failures surface the SES error code
and message verbatim (e.g. MessageRejected: Email address is not verified).
The sender address and optional reply-to addresses are fixed by configuration;
the tool has no from or reply_to parameter.
Configuration (environment variables)
| Variable | Required | Purpose |
|---|---|---|
SES_FROM_ADDRESS |
yes | verified SES identity to send from |
SES_REPLY_TO_ADDRESSES |
no | comma-separated reply-to addresses |
AWS_REGION |
yes | region of the SES identity |
ATTACHMENT_BASE_DIR |
no | directory attachments may be read from; attachments are rejected if unset |
AWS_PROFILE |
local only | profile for local testing; omit on EC2 (instance role is used) |
MCP client configuration
From PyPI (no checkout needed — uvx downloads and runs the published package):
{
"mcpServers": {
"ses-email-notification": {
"command": "uvx",
"args": ["ses-email-notification"],
"env": {
"AWS_REGION": "us-east-1",
"SES_FROM_ADDRESS": "noreply@example.com",
"SES_REPLY_TO_ADDRESSES": "support@example.com",
"ATTACHMENT_BASE_DIR": "/path/to/agent/output"
}
}
}
}
From a local checkout (testing with an AWS profile):
{
"mcpServers": {
"ses-email-notification": {
"command": "uv",
"args": ["run", "--directory", "/path/to/ses-email-notification", "ses-email-notification"],
"env": {
"AWS_PROFILE": "your-profile",
"AWS_REGION": "eu-central-1",
"SES_FROM_ADDRESS": "noreply@example.com",
"SES_REPLY_TO_ADDRESSES": "support@example.com,owner@example.com",
"ATTACHMENT_BASE_DIR": "/path/to/agent/output"
}
}
}
}
EC2 (instance role provides credentials — no AWS_PROFILE):
{
"mcpServers": {
"ses-email-notification": {
"command": "uv",
"args": ["run", "--directory", "/opt/ses-email-notification", "ses-email-notification"],
"env": {
"AWS_REGION": "eu-central-1",
"SES_FROM_ADDRESS": "noreply@example.com",
"SES_REPLY_TO_ADDRESSES": "support@example.com",
"ATTACHMENT_BASE_DIR": "/var/agent/output"
}
}
}
}
IAM policy for the EC2 instance role
ses:SendRawEmail is required for attachments. Scope the resource to your
verified identity ARN:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["ses:SendEmail", "ses:SendRawEmail"],
"Resource": "arn:aws:ses:REGION:ACCOUNT_ID:identity/example.com"
}
]
}
Limits & caveats
- Raw messages (sends with attachments) are capped at 10 MB after base64 encoding (~7 MB of actual files); the server rejects oversized sends before calling SES.
- SES sandbox: if the account is in sandbox mode, sends to unverified
recipients fail with
MessageRejected. Request production access before relying on this server.
Development
uv run pytest # unit tests (botocore Stubber, no AWS calls)
# manual smoke send against real SES:
AWS_PROFILE=your-profile AWS_REGION=eu-central-1 \
SES_FROM_ADDRESS=noreply@example.com \
SES_REPLY_TO_ADDRESSES=support@example.com \
uv run mcp dev src/ses_email_notification/server.py
Publishing to PyPI
Bump version in pyproject.toml first — PyPI rejects re-uploads of an
existing version.
uv build # builds sdist + wheel into dist/
uv publish --index testpypi --token <token> # dry run against test.pypi.org
uv publish --token <token> # real PyPI
Tokens come from https://pypi.org/manage/account/token/ (and the
test.pypi.org equivalent). UV_PUBLISH_TOKEN works instead of --token.
Release files for ses-email-notification 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ses_email_notification-0.1.2.tar.gz | 5.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ses_email_notification-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.2 kB
Release files / ses_email_notification-0.1.2.tar.gz
| Download URL | ses_email_notification-0.1.2.tar.gz |
|---|---|
| Size | 5.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6dd39519cfd767c205b4d1df10a3be80f3b5d34e79714781578cfb425ae20a3a
|
|
BLAKE2b-256 checksum How to use checksums |
20448f82c9ee3e34b0be78fcdd187e32d85db3ccae0af43507e253c7cce20f8e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / ses_email_notification-0.1.2-py3-none-any.whl
| Download URL | ses_email_notification-0.1.2-py3-none-any.whl |
|---|---|
| Size | 7.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
39106004e7ed166e4008faeb1843fdc1e7217d2dbb4450f48874351e464199b1
|
|
BLAKE2b-256 checksum How to use checksums |
5e6f2156ca2101d97e86504df8b4bd7c5eca22b359ad24045501a2d168f39626
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|