mailgun-apiMailgun API integration with managed OAuth. Transactional email service for sending, receiving, and tracking emails. Use this skill when users want to send emails, manage domains, routes, templates, mailing lists, or suppressions in Mailgun. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
Install via ClawdBot CLI:
clawdbot install byungkyu/mailgun-apiAccess the Mailgun API with managed OAuth authentication. Send transactional emails, manage domains, routes, templates, mailing lists, suppressions, and webhooks.
# List domains
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/mailgun/v3/domains')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
https://gateway.maton.ai/mailgun/v3/{resource}
Replace {resource} with the actual Mailgun API endpoint path. The gateway proxies requests to api.mailgun.net/v3 (US region) and automatically injects your OAuth token.
Regional Note: Mailgun has US and EU regions. The gateway defaults to US region (api.mailgun.net).
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Manage your Mailgun OAuth connections at https://ctrl.maton.ai.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=mailgun&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'mailgun'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "78b5a036-c621-40c2-b74b-276195735af2",
"status": "ACTIVE",
"creation_time": "2026-02-12T02:24:16.551210Z",
"last_updated_time": "2026-02-12T02:25:03.542838Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "mailgun",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple Mailgun connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/mailgun/v3/domains')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '78b5a036-c621-40c2-b74b-276195735af2')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If omitted, the gateway uses the default (oldest) active connection.
Important: Mailgun API uses application/x-www-form-urlencoded for POST/PUT requests, not JSON.
GET /mailgun/v3/domains
Returns all domains for the account.
GET /mailgun/v3/domains/{domain_name}
POST /mailgun/v3/domains
Content-Type: application/x-www-form-urlencoded
name=example.com&smtp_password=supersecret
DELETE /mailgun/v3/domains/{domain_name}
POST /mailgun/v3/{domain_name}/messages
Content-Type: application/x-www-form-urlencoded
from=sender@example.com&to=recipient@example.com&subject=Hello&text=Hello World
Parameters:
from (required) - Sender email addressto (required) - Recipient(s), comma-separatedcc - CC recipientsbcc - BCC recipientssubject (required) - Email subjecttext - Plain text bodyhtml - HTML bodytemplate - Name of stored template to useo:tag - Tag for trackingo:tracking - Enable/disable tracking (yes/no)o:tracking-clicks - Enable click trackingo:tracking-opens - Enable open trackingh:X-Custom-Header - Custom headers (prefix with h:)v:custom-var - Custom variables for templates (prefix with v:)POST /mailgun/v3/{domain_name}/messages.mime
Content-Type: multipart/form-data
to=recipient@example.com&message=<MIME content>
GET /mailgun/v3/{domain_name}/events
Query parameters:
begin - Start time (RFC 2822 or Unix timestamp)end - End timeascending - Sort order (yes/no)limit - Results per page (max 300)event - Filter by event type (accepted, delivered, failed, opened, clicked, unsubscribed, complained, stored)from - Filter by senderto - Filter by recipienttags - Filter by tagsRoutes are defined globally per account, not per domain.
GET /mailgun/v3/routes
Query parameters:
skip - Number of records to skiplimit - Number of records to returnPOST /mailgun/v3/routes
Content-Type: application/x-www-form-urlencoded
priority=0&description=My Route&expression=match_recipient(".*@example.com")&action=forward("https://example.com/webhook")
Parameters:
priority - Route priority (lower = higher priority)description - Route descriptionexpression - Filter expression (match_recipient, match_header, catch_all)action - Action(s) to take (forward, store, stop)GET /mailgun/v3/routes/{route_id}
PUT /mailgun/v3/routes/{route_id}
Content-Type: application/x-www-form-urlencoded
priority=1&description=Updated Route
DELETE /mailgun/v3/routes/{route_id}
GET /mailgun/v3/domains/{domain_name}/webhooks
POST /mailgun/v3/domains/{domain_name}/webhooks
Content-Type: application/x-www-form-urlencoded
id=delivered&url=https://example.com/webhook
Webhook types: accepted, delivered, opened, clicked, unsubscribed, complained, permanent_fail, temporary_fail
GET /mailgun/v3/domains/{domain_name}/webhooks/{webhook_type}
PUT /mailgun/v3/domains/{domain_name}/webhooks/{webhook_type}
Content-Type: application/x-www-form-urlencoded
url=https://example.com/new-webhook
DELETE /mailgun/v3/domains/{domain_name}/webhooks/{webhook_type}
GET /mailgun/v3/{domain_name}/templates
POST /mailgun/v3/{domain_name}/templates
Content-Type: application/x-www-form-urlencoded
name=my-template&description=Welcome email&template=<html><body>Hello {{name}}</body></html>
GET /mailgun/v3/{domain_name}/templates/{template_name}
DELETE /mailgun/v3/{domain_name}/templates/{template_name}
GET /mailgun/v3/lists/pages
POST /mailgun/v3/lists
Content-Type: application/x-www-form-urlencoded
address=newsletter@example.com&name=Newsletter&description=Monthly newsletter&access_level=readonly
Access levels: readonly, members, everyone
GET /mailgun/v3/lists/{list_address}
PUT /mailgun/v3/lists/{list_address}
Content-Type: application/x-www-form-urlencoded
name=Updated Newsletter
DELETE /mailgun/v3/lists/{list_address}
GET /mailgun/v3/lists/{list_address}/members/pages
POST /mailgun/v3/lists/{list_address}/members
Content-Type: application/x-www-form-urlencoded
address=member@example.com&name=John Doe&subscribed=yes
GET /mailgun/v3/lists/{list_address}/members/{member_address}
PUT /mailgun/v3/lists/{list_address}/members/{member_address}
Content-Type: application/x-www-form-urlencoded
name=Jane Doe&subscribed=no
DELETE /mailgun/v3/lists/{list_address}/members/{member_address}
# List bounces
GET /mailgun/v3/{domain_name}/bounces
# Add bounce
POST /mailgun/v3/{domain_name}/bounces
Content-Type: application/x-www-form-urlencoded
address=bounced@example.com&code=550&error=Mailbox not found
# Get bounce
GET /mailgun/v3/{domain_name}/bounces/{address}
# Delete bounce
DELETE /mailgun/v3/{domain_name}/bounces/{address}
# List unsubscribes
GET /mailgun/v3/{domain_name}/unsubscribes
# Add unsubscribe
POST /mailgun/v3/{domain_name}/unsubscribes
Content-Type: application/x-www-form-urlencoded
address=unsubscribed@example.com&tag=*
# Delete unsubscribe
DELETE /mailgun/v3/{domain_name}/unsubscribes/{address}
# List complaints
GET /mailgun/v3/{domain_name}/complaints
# Add complaint
POST /mailgun/v3/{domain_name}/complaints
Content-Type: application/x-www-form-urlencoded
address=complainer@example.com
# Delete complaint
DELETE /mailgun/v3/{domain_name}/complaints/{address}
# List whitelists
GET /mailgun/v3/{domain_name}/whitelists
# Add to whitelist
POST /mailgun/v3/{domain_name}/whitelists
Content-Type: application/x-www-form-urlencoded
address=allowed@example.com
# Delete from whitelist
DELETE /mailgun/v3/{domain_name}/whitelists/{address}
GET /mailgun/v3/{domain_name}/stats/total?event=delivered&event=opened
Query parameters:
event (required) - Event type(s): accepted, delivered, failed, opened, clicked, unsubscribed, complainedstart - Start date (RFC 2822 or Unix timestamp)end - End dateresolution - Data resolution (hour, day, month)duration - Period to show stats forGET /mailgun/v3/{domain_name}/tags
GET /mailgun/v3/{domain_name}/tags/{tag_name}
DELETE /mailgun/v3/{domain_name}/tags/{tag_name}
GET /mailgun/v3/ips
GET /mailgun/v3/ips/{ip_address}
GET /mailgun/v3/domains/{domain_name}/tracking
PUT /mailgun/v3/domains/{domain_name}/tracking/open
Content-Type: application/x-www-form-urlencoded
active=yes
PUT /mailgun/v3/domains/{domain_name}/tracking/click
Content-Type: application/x-www-form-urlencoded
active=yes
PUT /mailgun/v3/domains/{domain_name}/tracking/unsubscribe
Content-Type: application/x-www-form-urlencoded
active=yes&html_footer=<a href="%unsubscribe_url%">Unsubscribe</a>
GET /mailgun/v3/domains/{domain_name}/credentials
POST /mailgun/v3/domains/{domain_name}/credentials
Content-Type: application/x-www-form-urlencoded
login=alice&password=supersecret
DELETE /mailgun/v3/domains/{domain_name}/credentials/{login}
Mailgun uses cursor-based pagination:
{
"items": [...],
"paging": {
"first": "https://api.mailgun.net/v3/.../pages?page=first&limit=100",
"last": "https://api.mailgun.net/v3/.../pages?page=last&limit=100",
"next": "https://api.mailgun.net/v3/.../pages?page=next&limit=100",
"previous": "https://api.mailgun.net/v3/.../pages?page=prev&limit=100"
}
}
Use limit parameter to control page size (default: 100).
const formData = new URLSearchParams();
formData.append('from', 'sender@example.com');
formData.append('to', 'recipient@example.com');
formData.append('subject', 'Hello');
formData.append('text', 'Hello World!');
const response = await fetch(
'https://gateway.maton.ai/mailgun/v3/example.com/messages',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: formData.toString()
}
);
const result = await response.json();
console.log(result);
import os
import requests
response = requests.post(
'https://gateway.maton.ai/mailgun/v3/example.com/messages',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'},
data={
'from': 'sender@example.com',
'to': 'recipient@example.com',
'subject': 'Hello',
'text': 'Hello World!'
}
)
print(response.json())
import os
import requests
response = requests.get(
'https://gateway.maton.ai/mailgun/v3/domains',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
domains = response.json()
for domain in domains['items']:
print(f"{domain['name']}: {domain['state']}")
import os
import requests
headers = {'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
domain = 'example.com'
# Create route
route_response = requests.post(
'https://gateway.maton.ai/mailgun/v3/routes',
headers=headers,
data={
'priority': 0,
'description': 'Forward to webhook',
'expression': 'match_recipient("support@example.com")',
'action': 'forward("https://myapp.com/incoming-email")'
}
)
print(f"Route created: {route_response.json()}")
# Create webhook
webhook_response = requests.post(
f'https://gateway.maton.ai/mailgun/v3/domains/{domain}/webhooks',
headers=headers,
data={
'id': 'delivered',
'url': 'https://myapp.com/webhook/delivered'
}
)
print(f"Webhook created: {webhook_response.json()}")
application/x-www-form-urlencoded for POST/PUT requests, not JSONevent parametercurl -g when URLs contain brackets to disable glob parsingjq, environment variables may not expand correctly. Use Python examples instead.| Operation | Limit |
|-----------|-------|
| Sending | Varies by plan |
| API calls | No hard limit, but excessive requests may be throttled |
When rate limited, implement exponential backoff for retries.
| Status | Meaning |
|--------|---------|
| 400 | Bad request or missing Mailgun connection |
| 401 | Invalid or missing Maton API key |
| 403 | Forbidden (e.g., sandbox domain restrictions) |
| 404 | Resource not found |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from Mailgun API |
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
mailgun. For example:https://gateway.maton.ai/mailgun/v3/domainshttps://gateway.maton.ai/v3/domainsSandbox domains can only send to authorized recipients. To send emails:
AI Usage Analysis
Analysis is being generated⦠refresh in a few seconds.
Use the mcporter CLI to list, configure, auth, and call MCP servers/tools directly (HTTP or stdio), including ad-hoc servers, config edits, and CLI/type generation.
Connect to 100+ APIs (Google Workspace, Microsoft 365, GitHub, Notion, Slack, Airtable, HubSpot, etc.) with managed OAuth. Use this skill when users want to...
Build, debug, and deploy websites using HTML, CSS, JavaScript, and modern frameworks following production best practices.
YouTube Data API integration with managed OAuth. Search videos, manage playlists, access channel data, and interact with comments. Use this skill when users want to interact with YouTube. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
Scaffold, test, document, and debug REST and GraphQL APIs. Use when the user needs to create API endpoints, write integration tests, generate OpenAPI specs, test with curl, mock APIs, or troubleshoot HTTP issues.
Search for jobs across LinkedIn, Indeed, Glassdoor, ZipRecruiter, Google Jobs, Bayt, Naukri, and BDJobs using the JobSpy MCP server.