Prerequisites
To get the most out of this guide, you’ll need to:- Create a SendPost Account
- Flask 2.0+
- 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 flask sendpost-python-sdk python-dotenv
2. Environment Setup
Create a.env file:
SENDPOST_API_KEY=your_sub_account_api_key
SENDPOST_FROM_EMAIL=hello@playwithsendpost.io
SENDPOST_FROM_NAME=SendPost
FLASK_ENV=development
3. Basic Flask App Setup
Createapp.py:
Python
from flask import Flask
from dotenv import load_dotenv
import os
load_dotenv()
app = Flask(__name__)
app.config['SENDPOST_API_KEY'] = os.getenv('SENDPOST_API_KEY')
app.config['SENDPOST_FROM_EMAIL'] = os.getenv('SENDPOST_FROM_EMAIL')
app.config['SENDPOST_FROM_NAME'] = os.getenv('SENDPOST_FROM_NAME')
if __name__ == '__main__':
app.run(debug=True)
4. Create Email Utility
Createutils/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 flask import current_app
import re
class SendPostEmailService:
@staticmethod
def send_email(
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/dicts
subject: Email subject
html_body: HTML email body
text_body: Plain text email body (optional)
from_email: Sender email (optional)
from_name: Sender name (optional)
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:
configuration = sendpost_python_sdk.Configuration(
host="https://api.sendpost.io/api/v1"
)
configuration.api_key['subAccountAuth'] = current_app.config['SENDPOST_API_KEY']
with sendpost_python_sdk.ApiClient(configuration) as api_client:
email_message = EmailMessageObject()
# Set sender
email_message.var_from = EmailAddress(
email=from_email or current_app.config['SENDPOST_FROM_EMAIL'],
name=from_name or current_app.config['SENDPOST_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 SendPostEmailService._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:
current_app.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:
current_app.logger.error(f"SendPost error: {str(e)}")
return {
'success': False,
'message_id': None,
'error': str(e)
}
@staticmethod
def _html_to_text(html):
"""Simple HTML to text conversion"""
text = re.sub(r'<[^>]+>', '', html)
text = text.replace(' ', ' ')
text = text.replace('&', '&')
text = text.replace('<', '<')
text = text.replace('>', '>')
return text.strip()
5. Send Your First Email
Simple Route
Python
from flask import Flask, request, jsonify
from utils.email_service import SendPostEmailService
app = Flask(__name__)
@app.route('/api/send-email', methods=['POST'])
def send_email():
try:
data = request.get_json()
to = data.get('to')
subject = data.get('subject')
html_body = data.get('htmlBody')
if not all([to, subject, html_body]):
return jsonify({
'success': False,
'error': 'Missing required fields: to, subject, htmlBody'
}), 400
result = SendPostEmailService.send_email(
to=to,
subject=subject,
html_body=html_body,
text_body=data.get('textBody')
)
if result['success']:
return jsonify({
'success': True,
'messageId': result['message_id']
})
else:
return jsonify({
'success': False,
'error': result['error']
}), 500
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
6. Common Use Cases
Welcome Email Route
Python
@app.route('/api/welcome-email', methods=['POST'])
def send_welcome_email():
try:
data = request.get_json()
email = data.get('email')
first_name = data.get('firstName')
if not email or not first_name:
return jsonify({
'success': False,
'error': 'Missing required fields: email, firstName'
}), 400
result = SendPostEmailService.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']
)
if result['success']:
return jsonify({
'success': True,
'messageId': result['message_id']
})
else:
return jsonify({
'success': False,
'error': result['error']
}), 500
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
Password Reset Email
Python
@app.route('/api/password-reset', methods=['POST'])
def send_password_reset():
try:
data = request.get_json()
email = data.get('email')
reset_token = data.get('resetToken')
first_name = data.get('firstName', 'User')
if not email or not reset_token:
return jsonify({
'success': False,
'error': 'Missing required fields: email, resetToken'
}), 400
reset_url = f"{request.host_url}reset-password?token={reset_token}"
result = SendPostEmailService.send_email(
to={
'email': email,
'name': first_name,
'customFields': {
'firstName': first_name,
'resetUrl': reset_url
}
},
subject='Reset Your Password',
html_body='''
<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
)
if result['success']:
return jsonify({
'success': True,
'messageId': result['message_id']
})
else:
return jsonify({
'success': False,
'error': result['error']
}), 500
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
7. Using Blueprints
Createblueprints/email_bp.py:
Python
from flask import Blueprint, request, jsonify
from utils.email_service import SendPostEmailService
email_bp = Blueprint('email', __name__, url_prefix='/api/email')
@email_bp.route('/send', methods=['POST'])
def send_email():
"""Send a basic email"""
try:
data = request.get_json()
to = data.get('to')
subject = data.get('subject')
html_body = data.get('htmlBody')
if not all([to, subject, html_body]):
return jsonify({
'success': False,
'error': 'Missing required fields: to, subject, htmlBody'
}), 400
result = SendPostEmailService.send_email(
to=to,
subject=subject,
html_body=html_body,
text_body=data.get('textBody')
)
if result['success']:
return jsonify({
'success': True,
'messageId': result['message_id']
})
else:
return jsonify({
'success': False,
'error': result['error']
}), 500
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
}), 500
@email_bp.route('/welcome', methods=['POST'])
def welcome_email():
"""Send welcome email"""
# ... implementation similar to above ...
pass
@email_bp.route('/password-reset', methods=['POST'])
def password_reset_email():
"""Send password reset email"""
# ... implementation similar to above ...
pass
app.py:
Python
from blueprints.email_bp import email_bp
app.register_blueprint(email_bp)
8. Error Handling
Createerrors.py:
Python
from flask import jsonify
from werkzeug.exceptions import HTTPException
def register_error_handlers(app):
@app.errorhandler(400)
def bad_request(error):
return jsonify({
'success': False,
'error': 'Bad request',
'message': str(error)
}), 400
@app.errorhandler(500)
def internal_error(error):
return jsonify({
'success': False,
'error': 'Internal server error',
'message': str(error) if app.debug else 'An error occurred'
}), 500
@app.errorhandler(Exception)
def handle_exception(e):
if isinstance(e, HTTPException):
return e
app.logger.error(f"Unhandled exception: {str(e)}")
return jsonify({
'success': False,
'error': 'Internal server error',
'message': str(e) if app.debug else 'An error occurred'
}), 500
app.py:
Python
from errors import register_error_handlers
register_error_handlers(app)
9. Using Flask-Mail Style Interface (Optional)
Createextensions/email.py:
Python
from flask import current_app
from utils.email_service import SendPostEmailService
class Message:
def __init__(self, subject, recipients, body, html=None, sender=None):
self.subject = subject
self.recipients = recipients if isinstance(recipients, list) else [recipients]
self.body = body
self.html = html
self.sender = sender
class Mail:
def __init__(self, app=None):
self.app = app
if app is not None:
self.init_app(app)
def init_app(self, app):
self.app = app
def send(self, message):
"""Send email message using SendPost"""
html_body = message.html or message.body
text_body = message.body if message.html else None
result = SendPostEmailService.send_email(
to=message.recipients,
subject=message.subject,
html_body=html_body,
text_body=text_body,
from_email=message.sender
)
if not result['success']:
raise Exception(result['error'])
return result
Python
from extensions.email import Mail, Message
mail = Mail()
@app.route('/send')
def send():
msg = Message(
subject='Hello',
recipients=['user@example.com'],
body='Plain text body',
html='<h1>HTML body</h1>'
)
mail.send(msg)
return 'Email sent!'
Make sure your sender email domain is verified in your SendPost account before sending emails.
10. Next Steps
Explore more examples and use cases:Flask Documentation
Learn more about Flask framework
SendPost Python SDK
View the official SDK package on PyPI
Quickstart Example
View a complete working example on GitHub