API Reference
=============
This section documents the public classes and methods in django-forwardemail.
ForwardEmailService
-------------------
.. autoclass:: django_forwardemail.services.ForwardEmailService
:members:
:undoc-members:
:show-inheritance:
The main service class for sending email through the ForwardEmail API.
``EmailService`` is a backward-compatible alias for ``ForwardEmailService``.
send_email
~~~~~~~~~~
.. automethod:: django_forwardemail.services.ForwardEmailService.send_email
:no-index:
A keyword-only classmethod that sends a single email through the ForwardEmail
API.
**Parameters:**
* ``to`` (str, required): Recipient email address
* ``subject`` (str, required): Email subject line
* ``text`` (str, required): Plain text email content
* ``from_email`` (str, optional): Sender email address. If omitted, the sender
is built from the site's ``EmailConfiguration``
* ``html`` (str, optional): HTML email content for rich formatting
* ``reply_to`` (str, optional): Reply-to email address. If omitted, the site's
configured ``reply_to`` is used
* ``request`` (HttpRequest, optional): Django request object for automatic site
detection
* ``site`` (Site, optional): Django Site object for explicit site specification
* ``base_url`` (str, optional): Override for the ForwardEmail API base URL
**Returns:** ``dict[str, Any]`` -- the JSON response from the ForwardEmail API.
**Raises:**
* ``django.core.exceptions.ImproperlyConfigured``: when the site cannot be
determined, or the resolved site has no ``EmailConfiguration``
* ``Exception``: when the API request fails (a non-200 response or a network
error such as a timeout or connection error)
**Example:**
.. code-block:: python
from django_forwardemail.services import ForwardEmailService
ForwardEmailService.send_email(
to='user@example.com',
subject='Welcome!',
text='Welcome to our service',
html='
Welcome to our service
',
from_email='noreply@example.com',
reply_to='support@example.com',
)
extract_email
~~~~~~~~~~~~~
.. automethod:: django_forwardemail.services.ForwardEmailService.extract_email
:no-index:
A static method that returns the bare email address from a string. Given
``"Name "`` it returns ``"email@domain.com"``; a string that
is already a bare address is returned unchanged (stripped of whitespace).
EmailConfiguration Model
-------------------------
.. autoclass:: django_forwardemail.models.EmailConfiguration
:members:
:undoc-members:
:show-inheritance:
Django model for storing site-specific email configurations. Each Django
``Site`` has exactly one configuration (enforced by
``unique_together = [["site"]]``).
**Fields** (all required except the timestamps):
* ``site`` (ForeignKey to ``django.contrib.sites.models.Site``): the site this
configuration applies to
* ``api_key`` (CharField, max length 255): ForwardEmail API key
* ``from_email`` (EmailField): default sender email address
* ``from_name`` (CharField, max length 255): default sender display name
* ``reply_to`` (EmailField): default reply-to address
* ``created_at`` (DateTimeField): set automatically on creation
* ``updated_at`` (DateTimeField): set automatically on each save
**Example:**
.. code-block:: python
from django.contrib.sites.models import Site
from django_forwardemail.models import EmailConfiguration
site = Site.objects.get(domain='example.com')
config = EmailConfiguration.objects.create(
site=site,
api_key='your_api_key',
from_email='noreply@example.com',
from_name='Example Site',
reply_to='support@example.com',
)
ForwardEmailBackend
-------------------
.. autoclass:: django_forwardemail.backends.ForwardEmailBackend
:members:
:undoc-members:
:show-inheritance:
Django email backend that routes Django's standard email helpers through the
ForwardEmail API. It supports ``EmailMessage`` and ``EmailMultiAlternatives``
(HTML + text), extracts the reply-to address from the message, and accepts an
optional ``site`` via the connection or backend kwargs. Because the ForwardEmail
API accepts one recipient per request, the backend sends to the first recipient
of each message.
**send_messages**
.. automethod:: django_forwardemail.backends.ForwardEmailBackend.send_messages
:no-index:
Sends one or more ``EmailMessage`` instances.
* **Parameters:** ``email_messages`` (sequence of Django ``EmailMessage``
instances)
* **Returns:** the number of successfully sent messages (int). When
``fail_silently`` is true, failures are swallowed and excluded from the count.
**Example:**
.. code-block:: python
# settings.py
EMAIL_BACKEND = 'django_forwardemail.backends.ForwardEmailBackend'
# Usage with Django's email functions
from django.core.mail import send_mail
send_mail(
'Subject',
'Message',
'from@example.com',
['to@example.com'],
)
Django Admin Integration
------------------------
.. autoclass:: django_forwardemail.admin.EmailConfigurationAdmin
:members:
:undoc-members:
:show-inheritance:
Django admin interface for managing ``EmailConfiguration`` records. It is
registered automatically when the app is installed.
**Configuration:**
* ``list_display``: ``site``, ``from_name``, ``from_email``, ``reply_to``,
``updated_at``
* ``search_fields``: ``site__domain``, ``from_name``, ``from_email``,
``reply_to``
* ``list_filter``: ``site``, ``updated_at``, ``created_at``
* ``readonly_fields``: ``created_at``, ``updated_at``
* ``fieldsets``: site, an "Email Settings" group (API key and addresses), and a
collapsible "Timestamps" group
* The queryset uses ``select_related("site")`` and the site dropdown is ordered
by domain
App Configuration
-----------------
.. autoclass:: django_forwardemail.apps.DjangoForwardEmailConfig
:members:
:undoc-members:
:show-inheritance:
Django ``AppConfig`` for the package.
**Attributes:**
* ``default_auto_field``: ``"django.db.models.BigAutoField"``
* ``name``: ``"django_forwardemail"``
* ``verbose_name``: ``"Django ForwardEmail"``
Constants and Settings
----------------------
**API base URL**
``ForwardEmailService.DEFAULT_BASE_URL`` is ``"https://api.forwardemail.net"``.
Requests are sent to ``{base_url}/v1/emails``. The base URL can be overridden
per call via the ``base_url`` argument, or globally via the
``FORWARD_EMAIL_BASE_URL`` Django setting.
**Settings**
* ``FORWARD_EMAIL_BASE_URL`` (optional): overrides the ForwardEmail API base URL
* ``EMAIL_BACKEND``: set to ``"django_forwardemail.backends.ForwardEmailBackend"``
to use ForwardEmail with Django's standard email functions
There are no ``FORWARDEMAIL_*`` settings or environment variables -- API keys
and addresses live in the ``EmailConfiguration`` model.
Errors
------
The package does not define custom exception classes. Callers should handle:
* ``django.core.exceptions.ImproperlyConfigured`` -- raised by
``send_email()`` when the site cannot be resolved or has no
``EmailConfiguration``
* ``Exception`` -- raised by ``send_email()`` when the ForwardEmail API request
fails (a non-200 response or a network error)
Migration Support
-----------------
The package ships a single initial migration that creates the
``EmailConfiguration`` table and its foreign key to ``django.contrib.sites``.
.. code-block:: bash
# Apply migrations
python manage.py migrate
Testing
-------
``ForwardEmailService.send_email()`` issues a single ``requests.post`` call and
does not go through Django's ``EMAIL_BACKEND``. In tests, patch
``requests.post`` rather than relying on the ``locmem`` backend:
.. code-block:: python
from unittest.mock import patch
from django.test import TestCase
class MyTestCase(TestCase):
@patch('django_forwardemail.services.requests.post')
def test_email_sending(self, mock_post):
mock_post.return_value.status_code = 200
mock_post.return_value.json.return_value = {}
# ... call code that sends email ...
mock_post.assert_called_once()
Version Information
-------------------
.. autodata:: django_forwardemail.__version__
The current package version string.
.. code-block:: python
import django_forwardemail
print(django_forwardemail.__version__)
Logging
-------
The package logs through Python's standard ``logging`` module under the
``django_forwardemail`` logger name.
**Log levels used:**
* ``DEBUG``: ForwardEmail API request and response details (only emitted when
Django ``DEBUG`` is true)
* ``INFO``: general operational messages
* ``ERROR``: failed API requests and service errors
**Example configuration:**
.. code-block:: python
import logging
logger = logging.getLogger('django_forwardemail')
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(
logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
)
logger.addHandler(handler)