Send Email API Node.js Python: Complete Tutorial with Code Examples
Learn to send email via API in Node.js and Python with real code examples using GridInbox. Covers authentication, attachments, webhooks.

Every developer eventually needs to send email from their application. Whether it's transactional emails, notifications, or team replies, a reliable email API is essential. In this tutorial, you will learn to send email via API in Node.js and Python using the GridInbox REST API. We cover authentication, sending messages with attachments, handling webhooks, and real-world patterns you can copy and paste today.
GridInbox provides a REST API for sending and receiving email from unlimited aliases with custom domains.
GridInbox is a multi-tenant email alias management SaaS that works with AWS SES and Cloudflare Email Routing. Its REST API lets you programmatically send and receive email from any alias you own. You can manage shared team inboxes with role-based access control (RBAC), attach files, and handle incoming email via webhooks. All examples below use real API endpoints and real responses.
Prerequisites
- A GridInbox account with at least one verified domain
- An API key (found in your GridInbox dashboard under Settings > API Keys)
- Node.js 18+ or Python 3.8+ installed locally
- curl for quick testing (optional)
Authentication with the GridInbox API uses a simple bearer token in the Authorization header.
Every request to the GridInbox API must include an Authorization: Bearer YOUR_API_KEY header. Your API key is a 64-character string that identifies your account. Keep it secret; never expose it in client-side code.
Here is a quick test using curl to verify your key works:
curl -X GET https://api.gridinbox.com/v1/me \
-H "Authorization: Bearer gi_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
If your key is valid, you receive a JSON response with your account details and a 200 status code. A 401 means the key is invalid or missing.
Bearer Token: A credential string sent in the HTTP Authorization header to authenticate API requests. GridInbox uses bearer tokens exclusively.
How to send a simple email via API in Node.js and Python.
The POST /v1/send endpoint accepts a JSON body with from, to, subject, and body fields. Below are complete, runnable examples in both languages.
Node.js (using fetch, no external dependencies)
const API_KEY = 'gi_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
async function sendEmail() {
const response = await fetch('https://api.gridinbox.com/v1/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: 'hello@yourdomain.com',
to: ['user@example.com'],
subject: 'Hello from GridInbox',
body: 'This email was sent via the GridInbox API using Node.js.'
})
});
const data = await response.json();
console.log(data);
}
sendEmail();
Python (using requests)
import requests
API_KEY = 'gi_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
response = requests.post(
'https://api.gridinbox.com/v1/send',
headers={
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
},
json={
'from': 'hello@yourdomain.com',
'to': ['user@example.com'],
'subject': 'Hello from GridInbox',
'body': 'This email was sent via the GridInbox API using Python.'
}
)
print(response.json())
Both examples send a plain text email. The response includes an id field (e.g., "msg_abc123") that you can use to track delivery status later.
Attachments are supported via base64-encoded content in the API request.
To attach a file, add an attachments array to your request body. Each attachment requires a filename, content (base64-encoded string), and contentType (MIME type). Maximum attachment size per email is 25 MB total.
Node.js example with attachment
const fs = require('fs');
async function sendWithAttachment() {
const fileBuffer = fs.readFileSync('./invoice.pdf');
const base64Content = fileBuffer.toString('base64');
const response = await fetch('https://api.gridinbox.com/v1/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: 'billing@yourdomain.com',
to: ['client@example.com'],
subject: 'Your invoice',
body: 'Please find your invoice attached.',
attachments: [
{
filename: 'invoice.pdf',
content: base64Content,
contentType: 'application/pdf'
}
]
})
});
console.log(await response.json());
}
Python example with attachment
import base64
with open('invoice.pdf', 'rb') as f:
encoded = base64.b64encode(f.read()).decode('utf-8')
response = requests.post(
'https://api.gridinbox.com/v1/send',
headers={
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
},
json={
'from': 'billing@yourdomain.com',
'to': ['client@example.com'],
'subject': 'Your invoice',
'body': 'Please find your invoice attached.',
'attachments': [
{
'filename': 'invoice.pdf',
'content': encoded,
'contentType': 'application/pdf'
}
]
}
)
print(response.json())
GridInbox automatically attaches the file to the outgoing email. You can attach up to 10 files per email.
Webhooks notify your application when an email is delivered, bounced, or replied to.
GridInbox can send HTTP POST requests to a URL you specify whenever events occur. Common events include delivered, bounced, opened, and replied. Webhooks give you real-time feedback without polling.
Setting up a webhook endpoint in Node.js (Express)
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhooks/gridinbox', (req, res) => {
const event = req.body;
console.log('Received event:', event.type);
if (event.type === 'delivered') {
// Update your database: email delivered
console.log(`Email ${event.message_id} delivered`);
} else if (event.type === 'bounced') {
// Handle bounce: remove from list
console.log(`Email ${event.message_id} bounced: ${event.reason}`);
}
res.status(200).send('OK');
});
app.listen(3000, () => console.log('Webhook listener on port 3000'));
Setting up a webhook endpoint in Python (Flask)
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/webhooks/gridinbox', methods=['POST'])
def handle_webhook():
event = request.json
print(f"Received event: {event['type']}")
if event['type'] == 'delivered':
print(f"Email {event['message_id']} delivered")
elif event['type'] == 'bounced':
print(f"Email {event['message_id']} bounced: {event['reason']}")
return 'OK', 200
if __name__ == '__main__':
app.run(port=3000)
After deploying your endpoint, configure the webhook URL in the GridInbox dashboard under Webhooks. Choose which events to forward. GridInbox will retry failed deliveries up to 3 times with exponential backoff.
Error handling and rate limits keep your integration robust.
The GridInbox API returns standard HTTP status codes. A 429 status means you hit the rate limit (100 requests per second for paid plans). A 400 status indicates a validation error, such as a missing to field or an invalid email address. Always check response.ok or response.status in your code.
// Node.js: checking for errors
if (!response.ok) {
const error = await response.json();
console.error(`Error ${response.status}: ${error.message}`);
}
# Python: checking for errors
if response.status_code != 200:
error = response.json()
print(f"Error {response.status_code}: {error['message']}")
Retry with exponential backoff when you receive a 429. Wait at least 1 second before retrying, then double the wait each time. Most SDKs handle this automatically, but raw API users should implement it.
Real-world example: sending a transactional email with a template.
Suppose you run a SaaS and need to send a welcome email with the user's name and a link. Store your email templates on your server and substitute variables before sending.
// Node.js: welcome email with template
const template = `Hi {{name}},\n\nWelcome to our platform! Get started here: {{link}}\n\nBest,\nThe Team`;
async function sendWelcomeEmail(userName, userEmail, link) {
const body = template
.replace('{{name}}', userName)
.replace('{{link}}', link);
const response = await fetch('https://api.gridinbox.com/v1/send', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: 'welcome@yourdomain.com',
to: [userEmail],
subject: 'Welcome to our platform!',
body: body
})
});
return response.json();
}
In production, you might send 10,000 welcome emails per day. GridInbox handles that volume without issues when using AWS SES as the underlying provider. The API response includes a message_id you can store for future reference.
Best practices for sending email via API in Node.js and Python.
- Always validate email addresses server-side before sending. GridInbox does basic validation, but pre-checking reduces bounces.
- Use environment variables for your API key. Never hardcode it.
- Implement idempotency keys if you might retry the same request. GridInbox supports an optional idempotency_key header.
- Monitor your bounce rate. A rate above 5% can hurt your sender reputation. GridInbox's webhooks help you react fast.
- Test with a small batch first. Send 10 emails, check delivery, then ramp up.
Frequently Asked Questions
How do I send an email using Node.js and Python?
Use the GridInbox REST API endpoint POST /v1/send with a bearer token. In Node.js use fetch; in Python use the requests library. Pass the from, to, subject, and body fields in JSON.
What is the best email API for Node.js and Python developers?
GridInbox is a strong choice because it offers a simple REST API, supports unlimited aliases and custom domains, works with AWS SES, and provides webhooks for delivery tracking.
Can I send attachments with the email API?
Yes. Include an attachments array in your request body with base64-encoded content, filename, and MIME type. Maximum total attachment size is 25 MB with up to 10 files.
How do I handle email delivery status in my app?
Set up a webhook endpoint on your server and configure GridInbox to send events like delivered, bounced, or opened to that URL. GridInbox retries failed webhooks up to 3 times.
What are the rate limits for the GridInbox API?
Paid plans support 100 requests per second. Free plans have a limit of 10 requests per second. If you exceed the limit, you receive a 429 status code.
Do I need to use AWS SES or Cloudflare with GridInbox?
GridInbox works with AWS SES and Cloudflare Email Routing as underlying providers, but you do not need to manage them directly. GridInbox handles the configuration for you.




