# Email Testing

Email testing fixtures for capturing and testing Django email functionality. These fixtures provide access to Django's email outbox and DNS configuration for comprehensive email testing.

## Capabilities

### Email Outbox

Fixture providing access to Django's email outbox for testing sent emails.

```python { .api }
def mailoutbox() -> List[django.core.mail.EmailMessage]:
    """
    Access Django's email outbox for testing sent emails.
    
    Returns a list of EmailMessage objects that have been sent during
    the test. The outbox is automatically cleared between tests.
    Requires Django's locmem email backend or test email backend.
    
    Returns:
        List[EmailMessage]: List of email messages sent during test
    """
```

Usage example:
```python
from django.core import mail

def test_email_sending(mailoutbox):
    from django.core.mail import send_mail
    
    # Send an email
    send_mail(
        subject="Test Subject",
        message="Test message body",
        from_email="from@example.com",
        recipient_list=["to@example.com"],
    )
    
    # Check that email was sent
    assert len(mailoutbox) == 1
    email = mailoutbox[0]
    assert email.subject == "Test Subject"
    assert email.body == "Test message body"
    assert email.from_email == "from@example.com"
    assert email.to == ["to@example.com"]

def test_multiple_emails(mailoutbox):
    from django.core.mail import send_mail
    
    # Send multiple emails
    send_mail("Subject 1", "Body 1", "from@example.com", ["to1@example.com"])
    send_mail("Subject 2", "Body 2", "from@example.com", ["to2@example.com"])
    
    # Check all emails
    assert len(mailoutbox) == 2
    assert mailoutbox[0].subject == "Subject 1"
    assert mailoutbox[1].subject == "Subject 2"

def test_email_with_attachments(mailoutbox):
    from django.core.mail import EmailMessage
    
    email = EmailMessage(
        subject="Test with attachment",
        body="Message with attachment",
        from_email="from@example.com",
        to=["to@example.com"],
    )
    email.attach("test.txt", "File content", "text/plain")
    email.send()
    
    assert len(mailoutbox) == 1
    sent_email = mailoutbox[0]
    assert len(sent_email.attachments) == 1
    assert sent_email.attachments[0] == ("test.txt", "File content", "text/plain")
```

### Email DNS Patching

Fixture that patches DNS name used in email message headers.

```python { .api }
def django_mail_patch_dns() -> None:
    """
    Patch DNS name used in Django email message headers.
    
    Patches the DNS_NAME used by Django's email system to use
    a test-friendly DNS name instead of the system's actual DNS name.
    Automatically uses the value from django_mail_dnsname fixture.
    """
```

### Email DNS Name

Fixture providing the DNS name used for email testing.

```python { .api }
def django_mail_dnsname() -> str:
    """
    Provide DNS name for email testing.
    
    Returns the DNS name used in email message headers during testing.
    Default value is "fake-tests.example.com" but can be overridden
    by parametrizing this fixture.
    
    Returns:
        str: DNS name for email testing (default: "fake-tests.example.com")
    """
```

Usage example:
```python
def test_email_dns_name(mailoutbox, django_mail_dnsname):
    from django.core.mail import send_mail
    
    send_mail(
        subject="Test DNS",
        message="Test message",
        from_email="from@example.com",
        recipient_list=["to@example.com"],
    )
    
    # Check that custom DNS name is used
    assert django_mail_dnsname == "fake-tests.example.com"
    # Email will use this DNS name in headers

# Override DNS name for specific test
@pytest.fixture
def django_mail_dnsname():
    return "custom-test.example.com"

def test_custom_dns_name(mailoutbox, django_mail_dnsname):
    # This test will use "custom-test.example.com" as DNS name
    pass
```

## Email Configuration

For email testing to work properly, configure Django settings:

```python
# In Django settings for testing
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

# Or in test
def test_with_locmem_backend(settings, mailoutbox):
    settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
    # Now mailoutbox will capture emails
```

## Email Testing Types

```python { .api }
from django.core.mail import EmailMessage, EmailMultiAlternatives
from typing import List, Tuple, Optional, Any

# Email message types
EmailMessageType = EmailMessage
EmailList = List[EmailMessage]

# Email content types
EmailSubject = str
EmailBody = str
EmailAddress = str
EmailAddressList = List[str]

# Attachment types
AttachmentTuple = Tuple[str, str, str]  # (filename, content, mimetype)
AttachmentList = List[AttachmentTuple]

# DNS configuration
DnsName = str

# Email message structure
class EmailMessage:
    subject: str
    body: str
    from_email: str
    to: List[str]
    cc: List[str]
    bcc: List[str]
    reply_to: List[str]
    attachments: List[AttachmentTuple]
    extra_headers: dict[str, str]
    
    def send(self, fail_silently: bool = False) -> bool: ...
    def attach(self, filename: str, content: str, mimetype: str) -> None: ...
    def attach_file(self, path: str, mimetype: Optional[str] = None) -> None: ...

class EmailMultiAlternatives(EmailMessage):
    alternatives: List[Tuple[str, str]]  # (content, mimetype)
    
    def attach_alternative(self, content: str, mimetype: str) -> None: ...

# Mail outbox access
from django.core import mail
MailOutbox = mail.outbox
```