0
# Email Devices
1
2
One-time passwords delivered via email, useful for users who don't have smartphone access to authenticator apps or as a backup authentication method.
3
4
## Capabilities
5
6
### EmailDevice Model
7
8
```python { .api }
9
class EmailDevice(TimestampMixin, CooldownMixin, ThrottlingMixin, SideChannelDevice):
10
"""
11
Email-based OTP device with cooldown and throttling.
12
13
Fields:
14
- email: EmailField(blank=True) - Alternative email address
15
"""
16
17
email = models.EmailField(blank=True)
18
19
def generate_challenge(self, extra_context=None):
20
"""
21
Generate and email OTP token to user.
22
23
Parameters:
24
- extra_context: dict - Additional template context
25
26
Returns:
27
bool - True if challenge was generated and sent
28
"""
29
30
def get_subject(self) -> str:
31
"""Get email subject line."""
32
33
def send_mail(self, body, **kwargs):
34
"""
35
Send email with OTP token.
36
37
Parameters:
38
- body: str - Email body content
39
- **kwargs: Additional email parameters
40
"""
41
42
def get_cooldown_duration(self) -> int:
43
"""Return cooldown duration from settings."""
44
45
def get_throttle_factor(self) -> int:
46
"""Return throttle factor from settings."""
47
```
48
49
### Admin Interface
50
51
```python { .api }
52
class EmailDeviceAdmin(admin.ModelAdmin):
53
"""Admin interface for EmailDevice."""
54
```
55
56
### Configuration
57
58
```python { .api }
59
class OTPEmailSettings(Settings):
60
"""Email plugin settings with defaults."""
61
```
62
63
## Usage Examples
64
65
### Creating Email Devices
66
67
```python
68
from django_otp.plugins.otp_email.models import EmailDevice
69
70
# Create email device using user's email
71
device = EmailDevice.objects.create(
72
user=user,
73
name='Email OTP',
74
confirmed=True
75
)
76
77
# Create with alternative email
78
device = EmailDevice.objects.create(
79
user=user,
80
name='Backup Email',
81
email='backup@example.com', # Different from user.email
82
confirmed=True
83
)
84
```
85
86
### Generating and Verifying Email Tokens
87
88
```python
89
def send_email_otp(user):
90
"""Send OTP token via email."""
91
92
try:
93
device = EmailDevice.objects.get(user=user, confirmed=True)
94
95
# Check if generation is allowed (cooldown)
96
if device.generate_is_allowed() != True:
97
return False, "Please wait before requesting another code"
98
99
# Generate and send token
100
success = device.generate_challenge()
101
return success, "Code sent to email" if success else "Failed to send code"
102
103
except EmailDevice.DoesNotExist:
104
return False, "No email device configured"
105
106
def verify_email_otp(user, token):
107
"""Verify email OTP token."""
108
109
try:
110
device = EmailDevice.objects.get(user=user, confirmed=True)
111
112
if device.verify_token(token):
113
return True, "Token verified successfully"
114
else:
115
return False, "Invalid or expired token"
116
117
except EmailDevice.DoesNotExist:
118
return False, "No email device configured"
119
```
120
121
## Configuration Settings
122
123
```python
124
# settings.py
125
126
# Email settings
127
OTP_EMAIL_SENDER = 'noreply@example.com'
128
OTP_EMAIL_SUBJECT = 'Your verification code'
129
130
# Token validity (default: 300 seconds)
131
OTP_EMAIL_TOKEN_VALIDITY = 600
132
133
# Cooldown duration (default: 30 seconds)
134
OTP_EMAIL_COOLDOWN_DURATION = 60
135
136
# Throttling factor (default: 1)
137
OTP_EMAIL_THROTTLE_FACTOR = 2
138
139
# Email templates
140
OTP_EMAIL_BODY_TEMPLATE = 'Your verification code is: {token}'
141
OTP_EMAIL_BODY_TEMPLATE_PATH = 'otp/email_body.txt'
142
OTP_EMAIL_BODY_HTML_TEMPLATE_PATH = 'otp/email_body.html'
143
```
144
145
## Email Templates
146
147
### Text Template (email_body.txt)
148
149
```
150
Your verification code is: {{ token }}
151
152
This code will expire in {{ valid_minutes }} minutes.
153
154
If you did not request this code, please ignore this email.
155
```
156
157
### HTML Template (email_body.html)
158
159
```html
160
<h2>Verification Code</h2>
161
<p>Your verification code is: <strong>{{ token }}</strong></p>
162
<p>This code will expire in {{ valid_minutes }} minutes.</p>
163
<p><small>If you did not request this code, please ignore this email.</small></p>
164
```