Stdio MCP server for sending email notifications via AWS SES
Project description
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 is fixed by configuration — the tool has no from parameter.
Configuration (environment variables)
| Variable | Required | Purpose |
|---|---|---|
SES_FROM_ADDRESS |
yes | verified SES identity to send from |
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",
"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",
"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",
"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 \
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ses_email_notification-0.1.0.tar.gz.
File metadata
- Download URL: ses_email_notification-0.1.0.tar.gz
- Upload date:
- Size: 5.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80bf8c27ac2a49d78c3ce938c45f0099a2416d5b42c084154db33fa0935f71a0
|
|
| MD5 |
13932897fd7c3c70ef9a831b8c126ef9
|
|
| BLAKE2b-256 |
3393c577848ce7e3dfe1e7687f997e1966ce39e82de41211c5d049e060aefc56
|
File details
Details for the file ses_email_notification-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ses_email_notification-0.1.0-py3-none-any.whl
- Upload date:
- Size: 7.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d243117c2f2747a7715a8d10545ccf20ea260d2192e329e6b45d6e5a583cba2b
|
|
| MD5 |
14b6b9e071ff73b487783eabd1aea5f7
|
|
| BLAKE2b-256 |
af8dbc9064f0cd66894317d5af1825063648574477634e5959f9bfb39acc66ed
|