> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendpost.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Django Quickstart

> Learn how to send emails with SendPost in your Django application using custom email backend, views, and signals

## Prerequisites

To get the most out of this guide, you'll need to:

* [**Create a SendPost Account**](https://app.sendpost.io/register)
* [**Django 3.2+**](https://www.djangoproject.com/download/)
* [**Python 3.8+**](https://www.python.org/downloads/)
* A **Sub-Account API Key** from your SendPost dashboard

<Info>
  You can find your API keys in your [SendPost Dashboard](https://app.sendpost.io). Make sure to use your Sub-Account API Key for sending emails.
</Info>

## 1. Install Dependencies

```shellscript pip theme={null}
pip install sendpost-python-sdk django
```

## 2. Environment Setup

Add to your `settings.py`:

```python Python theme={null}
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')
```

Create a `.env` file:

```env theme={null}
SENDPOST_API_KEY=your_sub_account_api_key
SENDPOST_FROM_EMAIL=hello@playwithsendpost.io
SENDPOST_FROM_NAME=SendPost
```

## 3. Create Email Service

Create `services/email_service.py`:

```python Python theme={null}
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('&nbsp;', ' ')
        text = text.replace('&amp;', '&')
        text = text.replace('&lt;', '<')
        text = text.replace('&gt;', '>')
        return text.strip()

# Singleton instance
email_service = SendPostEmailService()
```

## 4. Send Your First Email

### In a View

Create `views.py`:

```python Python theme={null}
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)
```

Add to `urls.py`:

```python Python theme={null}
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

Create `views/welcome_email.py`:

```python Python theme={null}
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

Create `views/password_reset_email.py`:

```python Python theme={null}
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

Create `views/order_confirmation_email.py`:

```python Python theme={null}
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

Create `signals.py`:

```python Python theme={null}
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']
        )
```

Register signals in `apps.py`:

```python Python theme={null}
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

Create `tasks.py`:

```python Python theme={null}
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
```

Use in views:

```python Python theme={null}
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)

Create `backends/sendpost_backend.py`:

```python Python theme={null}
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
```

Add to `settings.py`:

```python Python theme={null}
EMAIL_BACKEND = 'myapp.backends.sendpost_backend.SendPostEmailBackend'
```

<Warning>
  Make sure your sender email domain is verified in your SendPost account before sending emails.
</Warning>

## 9. Next Steps

Explore more examples and use cases:

<Columns cols={3}>
  <Card title="Django Documentation" icon="django" href="https://docs.djangoproject.com/">
    Learn more about Django framework
  </Card>

  <Card title="SendPost Python SDK" icon="python" href="https://pypi.org/project/sendpost-python-sdk/">
    View the official SDK package on PyPI
  </Card>

  <Card title="Quickstart Example" icon="github" href="https://github.com/sendpost/sendpost-django-example">
    View a complete working example on GitHub
  </Card>
</Columns>
