diff --git a/djblets/mail/testing.py b/djblets/mail/testing.py
new file mode 100644
index 0000000000000000000000000000000000000000..7e720159c0418ec61f3b803163671be56ecfef85
--- /dev/null
+++ b/djblets/mail/testing.py
@@ -0,0 +1,41 @@
+"""Testing utilities for mail-related unit tests."""
+
+from __future__ import unicode_literals
+
+from django.core.cache import cache
+from dns import resolver as dns_resolver
+from dns.rdtypes.ANY.TXT import TXT
+from kgb import SpyAgency
+
+
+class DmarcDnsTestsMixin(SpyAgency):
+    """Mixin to help with e-mail tests that need to perform DMARC lookups.
+
+    This mixin makes it easy for unit tests to fake DMARC results, in order
+    to prevent the need from looking up real data from real records.
+
+    Unit tests can provide a mapping from domain names to TXT record strings
+    in the :py:attr:`dmarc_txt_records` dictionary. When a DMARC lookup is
+    performed, this dictionary will be used for the lookup.
+
+    Note that this mixin will also clear the memory cache before each test
+    run.
+
+    Attributes:
+        dmarc_txt_records (dict):
+            A dictionary of domain names to DMARC TXT record strings.
+    """
+
+    def setUp(self):
+        super(DmarcDnsTestsMixin, self).setUp()
+
+        self.dmarc_txt_records = {}
+
+        self.spy_on(dns_resolver.query, call_fake=self._dns_query)
+        cache.clear()
+
+    def _dns_query(self, qname, rdtype, *args, **kwargs):
+        try:
+            return [TXT(1, 16, [self.dmarc_txt_records[qname]])]
+        except KeyError:
+            raise dns_resolver.NXDOMAIN
diff --git a/djblets/mail/tests.py b/djblets/mail/tests.py
index 8cefca1d3c8ce965cba59eb7823c791dd28f38a2..b77c67d17fb42443fb00dd1f6cd40eafcacba09d 100644
--- a/djblets/mail/tests.py
+++ b/djblets/mail/tests.py
@@ -7,12 +7,11 @@ from django.core.cache import cache
 from django.test.utils import override_settings
 from django.utils.datastructures import MultiValueDict
 from dns import resolver as dns_resolver
-from dns.rdtypes.ANY.TXT import TXT
-from kgb import SpyAgency
 
 from djblets.mail.dmarc import (DmarcPolicy, get_dmarc_record,
                                 is_email_allowed_by_dmarc)
 from djblets.mail.message import EmailMessage
+from djblets.mail.testing import DmarcDnsTestsMixin
 from djblets.mail.utils import (build_email_address,
                                 build_email_address_for_user,
                                 build_email_address_via_service)
@@ -22,22 +21,6 @@ from djblets.testing.testcases import TestCase
 _CONSOLE_EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
 
 
-class DmarcDnsTestsMixin(SpyAgency):
-    def setUp(self):
-        super(DmarcDnsTestsMixin, self).setUp()
-
-        self.dmarc_txt_records = {}
-
-        self.spy_on(dns_resolver.query, call_fake=self._dns_query)
-        cache.clear()
-
-    def _dns_query(self, qname, rdtype, *args, **kwargs):
-        try:
-            return [TXT(1, 16, [self.dmarc_txt_records[qname]])]
-        except KeyError:
-            raise dns_resolver.NXDOMAIN
-
-
 class DmarcTests(DmarcDnsTestsMixin, TestCase):
     """Tests for DMARC support."""
 
diff --git a/docs/djblets/coderef/index.rst b/docs/djblets/coderef/index.rst
index ed1ccd38bb98bf7abd590e4d254f00ccd39845d5..958d69f87c89ae237737c488e31cc09aa80ff6aa 100644
--- a/docs/djblets/coderef/index.rst
+++ b/docs/djblets/coderef/index.rst
@@ -145,7 +145,10 @@ Mail Sending
 .. autosummary::
    :toctree: python
 
+   djblets.mail.dmarc
    djblets.mail.message
+   djblets.mail.testing
+   djblets.mail.utils
 
 
 Markdown Utilities and Extensions
