npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-simple-mail-sender

v1.1.0

Published

MCP server for sending email via SMTP

Readme

mcp-simple-mail-sender

A minimal MCP server that enables AI agents and automated pipelines to send email via any standard SMTP server.

Three tools, one purpose — start with send_email:

| Tool | What it does | When to use instead | |---|---|---| | send_email ⭐ | Send an email with structured arguments — recommended for most use cases | — | | send_email_json_arg | Send an email by passing the entire payload as a single JSON string | Your tooling can only template a single top-level string value | | send_email_flat_args | Send an email with a fully flat argument structure — no nested objects | Your tooling does not support nested arguments or nested templating |

For AI agents and standard MCP clients, use send_email. The other two tools exist for specific edge cases in pipeline tooling that imposes restrictions on argument structure.

MCP Configuration

{
  "mcpServers": {
    "mail": {
      "command": "npx",
      "args": ["-y", "mcp-simple-mail-sender"],
      "env": {
        "SMTP_HOST": "smtp.example.com",
        "SMTP_PORT": "587",
        "EMAIL_USER": "[email protected]",
        "EMAIL_PASS": "your-password"
      }
    }
  }
}

Or via Claude Code CLI:

claude mcp add simple-mail-sender \
  -e SMTP_HOST=smtp.example.com \
  -e [email protected] \
  -e EMAIL_PASS=your-password \
  -- npx -y mcp-simple-mail-sender

Environment Variables

| Variable | Required | Default | Description | |---|---|---|---| | EMAIL_USER | yes | — | SMTP auth username | | EMAIL_PASS | yes | — | SMTP auth password | | SMTP_HOST | yes | — | SMTP server hostname | | SMTP_PORT | no | 587 | SMTP server port | | SMTP_SECURE | no | false | true = force STARTTLS | | SMTP_IMPLICIT_TLS | no | false | true = wrap connection in TLS from the start (port 465 style) | | SMTP_EHLO_HOST | no | os.hostname() | Hostname sent in the EHLO greeting (client identity) | | SMTP_TRIGGER_FIRST | no | false | true = send wake bytes before waiting for the SMTP greeting (see below) | | SMTP_EHLO_FIRST | no | false | true = send EHLO immediately without waiting for a greeting, skipping non-250 responses | | SMTP_SEND_TIMEOUT | no | 60000 | Overall send timeout in milliseconds | | EMAIL_FROM | no | EMAIL_USER | Envelope From address |


Tool: send_email

Send an email via SMTP. Accepts standard structured arguments — this is the recommended tool for AI agents and MCP clients.

Parameters

| Parameter | Type | Required | Description | |---|---|---|---| | to | string | yes | Recipient(s), comma-separated | | subject | string | yes | Email subject | | body | string | yes | Email body | | html | boolean | no | Set true if body is HTML | | cc | string | no | CC recipients, comma-separated | | attachments | array | no | List of attachments (see below) |

Attachments

Each attachment object:

| Field | Type | Required | Description | |---|---|---|---| | filename | string | yes | Display name. If content is omitted, also used as the filesystem path to read from. | | content | string | no | Base64-encoded file content. When provided, filename is only the display name. | | contentType | string | no | MIME type, e.g. application/pdf |

Attach from base64 content:

{ "filename": "report.pdf", "content": "<base64>", "contentType": "application/pdf" }

Attach from filesystem path:

{ "filename": "/tmp/report.pdf" }

Example tool call

{
  "to": "[email protected]",
  "subject": "Important question",
  "body": "<h1>Where was Gondor when the Westfold fell?</h1>",
  "html": true,
  "attachments": [{ "filename": "/users/theoden/map.pdf" }]
}

Tool: send_email_json_arg

Send an email by passing the entire argument structure as a single JSON string.

Same functionality as send_email — the difference is only in how arguments are passed. Use this when your tooling can only apply templating or dynamic substitution to a single top-level string value, not to individual structured fields.

Parameters

| Parameter | Type | Required | Description | |---|---|---|---| | payload | string | yes | Full email definition as a JSON string (same fields as send_email) |

Example tool call

{
  "payload": "{\"to\":\"[email protected]\",\"subject\":\"Hello\",\"body\":\"Hi there.\",\"attachments\":[{\"filename\":\"/tmp/report.pdf\"}]}"
}

Example — Jinja pipeline where the whole payload is a single templated value

tool: send_email_json_arg
arguments:
  payload: >
    {
      "to": "{{ recipient }}",
      "subject": "{{ subject }}",
      "body": "{{ body }}",
      "attachments": [
        { "filename": "report.pdf", "content": "{{ report_b64 }}", "contentType": "application/pdf" },
        { "filename": "{{ log_path }}" }
      ]
    }

Tool: send_email_flat_args

Send an email using a fully flat argument structure — no nested objects.

Same functionality as send_email — the difference is only in how arguments are passed. Attachments are passed as individual top-level fields (attachment_0_filename, attachment_0_content, attachment_0_content_type, … up to attachment_8_*). Use this when your tooling does not support nested arguments or cannot template nested keys.

Parameters

| Parameter | Type | Required | Description | |---|---|---|---| | to | string | yes | Recipient(s), comma-separated | | subject | string | yes | Email subject | | body | string | yes | Email body (plain text or HTML) | | html | boolean | no | Set true if body is HTML | | cc | string | no | CC recipients, comma-separated | | attachment_N_filename | string | no | Display filename. If attachment_N_content is omitted, used as filesystem path. | | attachment_N_content | string | no | Base64-encoded file content. | | attachment_N_content_type | string | no | MIME type, e.g. application/pdf |

(N = 0–8, up to 9 attachments)

Example tool call

{
  "to": "[email protected]",
  "subject": "Monthly report",
  "body": "See attached.",
  "attachment_0_filename": "report.pdf",
  "attachment_0_content": "JVBERi0xLj...",
  "attachment_0_content_type": "application/pdf"
}

Example — Jinja YAML pipeline where only top-level keys are templated

# Every value is a top-level key — Jinja resolves all {{ }} tokens correctly,
# including attachment content that would be inaccessible inside send_email's nested array.
tool: send_email_flat_args
arguments:
  to: [email protected]
  subject: "Pipeline report {{ run_id }}"
  body: "Run {{ run_id }} completed."
  attachment_0_filename: report.pdf
  attachment_0_content: "{{ report_b64 }}"
  attachment_0_content_type: application/pdf
  attachment_1_filename: "{{ log_path }}"

Non-standard SMTP proxies

SMTP_TRIGGER_FIRST

Some SMTP relays use a "client-first" TCP proxy that stays silent after the TCP handshake, waiting for the client to send data before forwarding to the real SMTP backend. Standard SMTP clients (which wait for the server's 220 greeting) will hang indefinitely.

Setting SMTP_TRIGGER_FIRST=true sends a small burst of bytes immediately on connect to wake the proxy. A trailing \r\n is appended so the SMTP backend treats the bytes as a complete (invalid) command, flushes its 500 error response, and is in a clean state when EHLO arrives. Without the \r\n, the binary bytes would linger in the server's command buffer and get prepended to EHLO, causing a 500 5.5.2 bad chars in command error.

Use SMTP_TRIGGER_FIRST=true when connections hang silently and never receive a 220 greeting.

The default EHLO hostname is os.hostname() (your machine's hostname), which works for most servers. Override with SMTP_EHLO_HOST if the server rejects it — common reasons are loop protection (server's own hostname detected) or blocklisting of generic names.

SMTP_IMPLICIT_TLS

Use SMTP_IMPLICIT_TLS=true for servers that expect a TLS handshake immediately on connect (typically port 465). This is distinct from STARTTLS (SMTP_SECURE), which upgrades a plain connection mid-session.

SMTP_EHLO_FIRST

Use SMTP_EHLO_FIRST=true for proxies that need the client to speak first but where EHLO itself is the right wake signal (rather than garbage bytes). The client sends EHLO immediately without waiting for 220, and skips any non-250 responses until the EHLO acknowledgement arrives.

Troubleshooting

To test your SMTP configuration without going through the MCP layer, clone the repo and run test.js directly:

git clone https://github.com/xstast24/mcp-simple-mail-sender.git
cd mcp-simple-mail-sender
npm install

SMTP_HOST=smtp.example.com \
[email protected] \
EMAIL_PASS=your-password \
node test.js [email protected] "Test subject" "Test body"

Add any extra flags (SMTP_TRIGGER_FIRST=true, SMTP_EHLO_HOST=myhostname, etc.) to the same command.

Note: test.js is not included in the published npm package — cloning the repository is required to use it.

Running locally

npm install
node index.js   # starts the MCP server on stdio