Updated 2026-10-08
How to Configure SMTP Email in Django
To send Django email through an SMTP relay, set EMAIL_BACKEND to django.core.mail.backends.smtp.EmailBackend, EMAIL_HOST to smtp.bulko.io, EMAIL_PORT to 587 and EMAIL_USE_TLS to True in settings.py, and load EMAIL_HOST_USER and EMAIL_HOST_PASSWORD from environment variables. On Django 6.1 and newer you can put the same values into the new MAILERS setting instead.
Django SMTP settings
| Field | Value |
|---|---|
| EMAIL_BACKEND | django.core.mail.backends.smtp.EmailBackend |
| EMAIL_HOST | smtp.bulko.io |
| EMAIL_PORT | 587 (or 2525; 465 only with EMAIL_USE_SSL) |
| EMAIL_USE_TLS | True for 587 and 2525 (STARTTLS) |
| EMAIL_USE_SSL | False for 587; True only for port 465 (never both True) |
| EMAIL_HOST_USER | Your SMTP username, e.g. smtp_xxxxxxxxxxxxxxxx |
| EMAIL_HOST_PASSWORD | Your SMTP password, read from an environment variable |
| DEFAULT_FROM_EMAIL | An address on your domain, e.g. Your App <[email protected]> |
| EMAIL_TIMEOUT | 30 (seconds; without it a blocked port can hang a request) |
Step-by-step setup
- Buy an SMTP package on the Bulko SMTP Relay page and copy the username and password from Dashboard -> SMTP Access.
- Export them as environment variables on the server, for example
SMTP_USERNAMEandSMTP_PASSWORD, so the password never lands in your repository. - In
settings.pysetEMAIL_BACKEND,EMAIL_HOST = "smtp.bulko.io",EMAIL_PORT = 587andEMAIL_USE_TLS = True, and readEMAIL_HOST_USERandEMAIL_HOST_PASSWORDfromos.environ. - Pick exactly one encryption flag.
EMAIL_USE_TLSmeans STARTTLS (explicit TLS) on 587 or 2525.EMAIL_USE_SSLmeans implicit TLS on 465. Django refuses to start sending if both are True. - Set
DEFAULT_FROM_EMAIL(used whenfrom_emailisNone) andSERVER_EMAIL(used for error mails toADMINS) to addresses on your own domain. Verify the domain under Sending Domains in the Bulko dashboard for aligned SPF, DKIM and DMARC. - Add
EMAIL_TIMEOUT = 30so a blocked port fails with an error instead of hanging a web request. - On Django 6.1 or newer, optionally move the same values into
MAILERS["default"]["OPTIONS"](keyshost,port,use_tls,use_ssl,username,password,timeout) and remove the oldEMAIL_*settings.
EMAIL_* settings vs MAILERS in Django 6.1
Django 6.1 added a MAILERS setting and deprecated EMAIL_BACKEND, EMAIL_HOST, EMAIL_PORT, EMAIL_HOST_USER, EMAIL_HOST_PASSWORD, EMAIL_USE_TLS, EMAIL_USE_SSL and EMAIL_TIMEOUT. The old settings keep working with deprecation warnings until Django 7.0. Both forms are shown in the code block; use one, not both. For more on port choice see the SMTP ports guide.
settings.py
# settings.py
import os
# Django 6.0 and earlier (still works in 6.1 with deprecation warnings)
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.bulko.io"
EMAIL_PORT = 587
EMAIL_USE_TLS = True # STARTTLS on 587 or 2525
EMAIL_USE_SSL = False # for port 465 set EMAIL_USE_SSL = True, EMAIL_USE_TLS = False
EMAIL_HOST_USER = os.environ["SMTP_USERNAME"]
EMAIL_HOST_PASSWORD = os.environ["SMTP_PASSWORD"]
EMAIL_TIMEOUT = 30
DEFAULT_FROM_EMAIL = "Your App <[email protected]>"
SERVER_EMAIL = "[email protected]"
# Django 6.1+: the same settings as a MAILERS entry (replaces EMAIL_* above)
# MAILERS = {
# "default": {
# "BACKEND": "django.core.mail.backends.smtp.EmailBackend",
# "OPTIONS": {
# "host": "smtp.bulko.io",
# "port": 587,
# "use_tls": True,
# "username": os.environ["SMTP_USERNAME"],
# "password": os.environ["SMTP_PASSWORD"],
# "timeout": 30,
# },
# },
# }
# Test:
# python manage.py shell
# >>> from django.core.mail import send_mail
# >>> send_mail("Django SMTP test", "It works.", None, ["[email protected]"], fail_silently=False)
# 1
Send a test email
Run python manage.py shell and call send_mail("Django SMTP test", "It works.", None, ["[email protected]"], fail_silently=False) after from django.core.mail import send_mail. A return value of 1 means one message was accepted by the relay. Check the inbox and the message headers to confirm it came through smtp.bulko.io.
Keep fail_silently=False while testing (pass it as a keyword: Django 6.0 deprecated passing it positionally), so any SMTP error is raised as an exception with the server reply code.
Troubleshooting
| Problem | Fix |
|---|---|
| SMTPAuthenticationError: (535, ...) | Username or password is wrong, or the environment variables are not set in the process running Django. Print len(settings.EMAIL_HOST_PASSWORD) in the shell to check. See https://bulko.io/en/smtp-errors/535/ |
| ValueError: EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive | Only one can be True. Use EMAIL_USE_TLS with 587 or 2525, or EMAIL_USE_SSL with 465. |
| ssl.SSLError: wrong version number | Port and flag do not match: EMAIL_USE_SSL on 587 or EMAIL_USE_TLS on 465. Fix the pair. |
| TimeoutError or the request hangs | Outbound 587 or 465 is blocked by your host. Set EMAIL_PORT = 2525 with EMAIL_USE_TLS = True, and keep EMAIL_TIMEOUT set. |
| Mail prints to the console instead of sending | EMAIL_BACKEND is the console backend (common in dev settings), or a MAILERS entry overrides it. Check which settings module is loaded. |
| SMTPDataError: (554, b'5.7.1 ...') | The AI content filter rejected the message for phishing, malware, impersonation or scam patterns. Review the content; see https://bulko.io/en/acceptable-use/ |
FAQ
Should Django use EMAIL_USE_TLS or EMAIL_USE_SSL?
Use EMAIL_USE_TLS = True with port 587 (STARTTLS). EMAIL_USE_SSL = True is only for port 465. Never set both.
Are EMAIL_HOST and EMAIL_PORT deprecated?
In Django 6.1 they are deprecated in favor of the MAILERS setting, but they still work with warnings until Django 7.0. On Django 6.0 and earlier they are the only option.
Can Django receive replies through this SMTP server?
No. Bulko SMTP is outgoing only, with no IMAP or inbox. Replies go to the From or Reply-To address you set.
What is the daily sending limit?
2,000 emails per day per SMTP account by default. Contact [email protected] to raise it.
How much does it cost?
One-time packages: $5 for 5,000 emails, $15 for 20,000, $30 for 50,000, $60 for 150,000. Unused emails never expire. There is no free SMTP trial.
Does this work with django-allauth password resets and error emails?
Yes. Anything that uses django.core.mail (password resets, allauth, mail_admins) goes through the configured SMTP backend.
Get SMTP credentials for Django
One-time payment by card or crypto, no subscription. Unused emails never expire. 2,000 emails per day per SMTP account.
What you can send: Acceptable Use Policy.