Prerequisites
To get the most out of this guide, you’ll need to:- Create a SendPost Account
- Django 3.2+
- Python 3.8+
- A Sub-Account API Key from your SendPost dashboard
You can find your API keys in your SendPost Dashboard. Make sure to use your Sub-Account API Key for sending emails.
1. Install Dependencies
pip
pip install sendpost-python-sdk django
2. Environment Setup
Add to yoursettings.py:
Python
import os
from pathlib import Path
# Build paths inside the project
BASE_DIR = Path(__file__).resolve().parent.parent
# SendPost Configuration
SENDPOST_API_KEY = os.environ.get('SENDPOST_API_KEY', '')
SENDPOST_FROM_EMAIL = os.environ.get('SENDPOST_FROM_EMAIL', 'hello@playwithsendpost.io')
SENDPOST_FROM_NAME = os.environ.get('SENDPOST_FROM_NAME', 'SendPost')
.env file:
SENDPOST_API_KEY=your_sub_account_api_key
SENDPOST_FROM_EMAIL=hello@playwithsendpost.io
SENDPOST_FROM_NAME=SendPost
3. Create Email Service
Createservices/email_service.py:
Python
import sendpost_python_sdk
from sendpost_python_sdk.api import EmailApi
from sendpost_python_sdk.models import EmailMessageObject, EmailAddress, Recipient
from django.conf import settings
import logging
logger = logging.getLogger(__name__)
class SendPostEmailService:
def __init__(self):
self.configuration = sendpost_python_sdk.Configuration(
host="https://api.sendpost.io/api/v1"
)
self.configuration.api_key['subAccountAuth'] = settings.SENDPOST_API_KEY
self.from_email = settings.SENDPOST_FROM_EMAIL
self.from_name = settings.SENDPOST_FROM_NAME
def send_email(
self,
to,
subject,
html_body,
text_body=None,
from_email=None,
from_name=None,
groups=None,
track_opens=True,
track_clicks=True,
custom_fields=None,
):
"""
Send an email using SendPost API.
Args:
to: Email address (str) or list of Recipient objects
subject: Email subject
html_body: HTML email body
text_body: Plain text email body (optional)
from_email: Sender email (optional, uses default)
from_name: Sender name (optional, uses default)
groups: List of groups for email classification
track_opens: Enable open tracking
track_clicks: Enable click tracking
custom_fields: Dict of custom fields for personalization
Returns:
dict: {'success': bool, 'message_id': str or None, 'error': str or None}
"""
try:
with sendpost_python_sdk.ApiClient(self.configuration) as api_client:
email_message = EmailMessageObject()
# Set sender
email_message.var_from = EmailAddress(
email=from_email or self.from_email,
name=from_name or self.from_name
)
# Handle recipients
if isinstance(to, str):
recipients = [Recipient(email=to)]
elif isinstance(to, list):
recipients = []
for recipient in to:
if isinstance(recipient, str):
recipients.append(Recipient(email=recipient))
elif isinstance(recipient, dict):
recipients.append(Recipient(
email=recipient.get('email'),
name=recipient.get('name'),
custom_fields=recipient.get('customFields') or custom_fields
))
else:
recipients.append(recipient)
else:
recipients = [Recipient(email=to)]
email_message.to = recipients
email_message.subject = subject
email_message.html_body = html_body
email_message.text_body = text_body or self._html_to_text(html_body)
email_message.track_opens = track_opens
email_message.track_clicks = track_clicks
if groups:
email_message.groups = groups if isinstance(groups, list) else [groups]
response = EmailApi(api_client).send_email(email_message)[0]
return {
'success': True,
'message_id': response.message_id,
'data': response
}
except sendpost_python_sdk.exceptions.ApiException as e:
logger.error(f"SendPost API error: {e.status} - {e.body}")
return {
'success': False,
'message_id': None,
'error': f"API Error {e.status}: {e.body}"
}
except Exception as e:
logger.error(f"SendPost error: {str(e)}")
return {
'success': False,
'message_id': None,
'error': str(e)
}
def _html_to_text(self, html):
"""Simple HTML to text conversion"""
import re
text = re.sub(r'<[^>]+>', '', html)
text = text.replace(' ', ' ')
text = text.replace('&', '&')
text = text.replace('<', '<')
text = text.replace('>', '>')
return text.strip()
# Singleton instance
email_service = SendPostEmailService()
4. Send Your First Email
In a View
Createviews.py:
Python
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
import json
from services.email_service import email_service
@csrf_exempt
@require_http_methods(["POST"])
def send_email_view(request):
try:
data = json.loads(request.body)
to = data.get('to')
subject = data.get('subject')
html_body = data.get('htmlBody')
if not all([to, subject, html_body]):
return JsonResponse({
'success': False,
'error': 'Missing required fields: to, subject, htmlBody'
}, status=400)
result = email_service.send_email(
to=to,
subject=subject,
html_body=html_body,
text_body=data.get('textBody')
)
if result['success']:
return JsonResponse({
'success': True,
'messageId': result['message_id']
})
else:
return JsonResponse({
'success': False,
'error': result['error']
}, status=500)
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)
urls.py:
Python
from django.urls import path
from . import views
urlpatterns = [
path('api/send-email/', views.send_email_view, name='send_email'),
]
5. Common Use Cases
Welcome Email
Createviews/welcome_email.py:
Python
from services.email_service import email_service
from django.http import JsonResponse
def send_welcome_email(email, first_name):
"""Send welcome email to new user"""
result = email_service.send_email(
to={
'email': email,
'name': first_name,
'customFields': {'firstName': first_name}
},
subject='Welcome {{firstName}}!',
html_body='''
<h1>Welcome, {{firstName}}!</h1>
<p>Thank you for joining us. We're excited to have you on board.</p>
<p>Get started by exploring our features:</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
<li>Feature 3</li>
</ul>
<p>If you have any questions, just reply to this email.</p>
<p><a href="{{unsubscribe}}">Unsubscribe</a></p>
''',
text_body='''
Welcome, {{firstName}}!
Thank you for joining us. We're excited to have you on board.
Get started by exploring our features:
- Feature 1
- Feature 2
- Feature 3
If you have any questions, just reply to this email.
Unsubscribe: {{unsubscribe}}
''',
groups=['welcome']
)
return result
Password Reset Email
Createviews/password_reset_email.py:
Python
from services.email_service import email_service
from django.conf import settings
def send_password_reset_email(email, reset_token, first_name):
"""Send password reset email"""
reset_url = f"{settings.APP_URL}/reset-password?token={reset_token}"
result = email_service.send_email(
to={
'email': email,
'name': first_name,
'customFields': {
'firstName': first_name,
'resetUrl': reset_url
}
},
subject='Reset Your Password',
html_body=f'''
<h2>Hello {{firstName}},</h2>
<p>We received a request to reset your password. Click the button below:</p>
<p>
<a href="{{resetUrl}}" style="background-color: #5750EC; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">
Reset Password
</a>
</p>
<p>Or copy and paste this link: {{resetUrl}}</p>
<p>This link will expire in 1 hour.</p>
<p>If you didn't request this, please ignore this email.</p>
''',
text_body='''
Hello {{firstName}},
We received a request to reset your password. Click the link below:
{{resetUrl}}
This link will expire in 1 hour.
If you didn't request this, please ignore this email.
''',
groups=['password-reset'],
track_clicks=True
)
return result
Order Confirmation Email
Createviews/order_confirmation_email.py:
Python
from services.email_service import email_service
def send_order_confirmation_email(email, first_name, order_id, items, total):
"""Send order confirmation email"""
result = email_service.send_email(
to={
'email': email,
'name': first_name,
'customFields': {
'firstName': first_name,
'orderId': order_id,
'items': items,
'total': f"{total:.2f}"
}
},
subject='Order {{orderId}} Confirmed',
html_body='''
<h1>Thank you for your order, {{firstName}}!</h1>
<p>Your order <strong>{{orderId}}</strong> has been confirmed.</p>
<h2>Order Details</h2>
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="background-color: #f5f5f5;">
<th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Item</th>
<th style="padding: 12px; text-align: left; border: 1px solid #ddd;">Quantity</th>
<th style="padding: 12px; text-align: right; border: 1px solid #ddd;">Price</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td style="padding: 12px; border: 1px solid #ddd;">{{name}}</td>
<td style="padding: 12px; border: 1px solid #ddd;">{{quantity}}</td>
<td style="padding: 12px; text-align: right; border: 1px solid #ddd;">${{price}}</td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td colspan="2" style="padding: 12px; text-align: right; border: 1px solid #ddd;"><strong>Total:</strong></td>
<td style="padding: 12px; text-align: right; border: 1px solid #ddd;"><strong>${{total}}</strong></td>
</tr>
</tfoot>
</table>
<p>We'll send you a shipping confirmation once your order is on its way.</p>
<p><a href="{{unsubscribe}}">Unsubscribe from order updates</a></p>
''',
groups=['order-confirmation']
)
return result
6. Using Django Signals
Createsignals.py:
Python
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from services.email_service import email_service
@receiver(post_save, sender=User)
def send_welcome_email_on_user_creation(sender, instance, created, **kwargs):
"""Send welcome email when a new user is created"""
if created and instance.email:
email_service.send_email(
to={
'email': instance.email,
'name': instance.first_name or instance.username,
'customFields': {
'firstName': instance.first_name or instance.username
}
},
subject='Welcome {{firstName}}!',
html_body='''
<h1>Welcome, {{firstName}}!</h1>
<p>Thank you for joining us.</p>
<p><a href="{{unsubscribe}}">Unsubscribe</a></p>
''',
groups=['welcome']
)
apps.py:
Python
from django.apps import AppConfig
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'
def ready(self):
import myapp.signals # noqa
7. Using Celery for Async Email Sending
Createtasks.py:
Python
from celery import shared_task
from services.email_service import email_service
import logging
logger = logging.getLogger(__name__)
@shared_task
def send_email_async(to, subject, html_body, text_body=None, **kwargs):
"""Send email asynchronously using Celery"""
try:
result = email_service.send_email(
to=to,
subject=subject,
html_body=html_body,
text_body=text_body,
**kwargs
)
return result
except Exception as e:
logger.error(f"Failed to send email: {str(e)}")
raise
Python
from .tasks import send_email_async
def send_email_view(request):
# ... validation code ...
# Send asynchronously
send_email_async.delay(
to=to,
subject=subject,
html_body=html_body
)
return JsonResponse({'success': True, 'message': 'Email queued'})
8. Custom Email Backend (Optional)
Createbackends/sendpost_backend.py:
Python
from django.core.mail.backends.base import BaseEmailBackend
from services.email_service import email_service
class SendPostEmailBackend(BaseEmailBackend):
def send_messages(self, email_messages):
"""Send email messages using SendPost"""
sent_count = 0
for message in email_messages:
try:
result = email_service.send_email(
to=message.to[0] if message.to else None,
subject=message.subject,
html_body=message.body if hasattr(message, 'alternatives') and message.alternatives else message.body,
text_body=message.body if not hasattr(message, 'alternatives') or not message.alternatives else None
)
if result['success']:
sent_count += 1
except Exception as e:
if not self.fail_silently:
raise
return sent_count
settings.py:
Python
EMAIL_BACKEND = 'myapp.backends.sendpost_backend.SendPostEmailBackend'
Make sure your sender email domain is verified in your SendPost account before sending emails.
9. Next Steps
Explore more examples and use cases:Django Documentation
Learn more about Django framework
SendPost Python SDK
View the official SDK package on PyPI
Quickstart Example
View a complete working example on GitHub