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.

Hostsmtp.bulko.io
Port587 · 465 · 2525
EncryptionSTARTTLS · SSL
Loginfrom dashboard

Django SMTP settings

FieldValue
EMAIL_BACKENDdjango.core.mail.backends.smtp.EmailBackend
EMAIL_HOSTsmtp.bulko.io
EMAIL_PORT587 (or 2525; 465 only with EMAIL_USE_SSL)
EMAIL_USE_TLSTrue for 587 and 2525 (STARTTLS)
EMAIL_USE_SSLFalse for 587; True only for port 465 (never both True)
EMAIL_HOST_USERYour SMTP username, e.g. smtp_xxxxxxxxxxxxxxxx
EMAIL_HOST_PASSWORDYour SMTP password, read from an environment variable
DEFAULT_FROM_EMAILAn address on your domain, e.g. Your App <[email protected]>
EMAIL_TIMEOUT30 (seconds; without it a blocked port can hang a request)

Step-by-step setup

  1. Buy an SMTP package on the Bulko SMTP Relay page and copy the username and password from Dashboard -> SMTP Access.
  2. Export them as environment variables on the server, for example SMTP_USERNAME and SMTP_PASSWORD, so the password never lands in your repository.
  3. In settings.py set EMAIL_BACKEND, EMAIL_HOST = "smtp.bulko.io", EMAIL_PORT = 587 and EMAIL_USE_TLS = True, and read EMAIL_HOST_USER and EMAIL_HOST_PASSWORD from os.environ.
  4. Pick exactly one encryption flag. EMAIL_USE_TLS means STARTTLS (explicit TLS) on 587 or 2525. EMAIL_USE_SSL means implicit TLS on 465. Django refuses to start sending if both are True.
  5. Set DEFAULT_FROM_EMAIL (used when from_email is None) and SERVER_EMAIL (used for error mails to ADMINS) to addresses on your own domain. Verify the domain under Sending Domains in the Bulko dashboard for aligned SPF, DKIM and DMARC.
  6. Add EMAIL_TIMEOUT = 30 so a blocked port fails with an error instead of hanging a web request.
  7. On Django 6.1 or newer, optionally move the same values into MAILERS["default"]["OPTIONS"] (keys host, port, use_tls, use_ssl, username, password, timeout) and remove the old EMAIL_* 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

ProblemFix
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 exclusiveOnly one can be True. Use EMAIL_USE_TLS with 587 or 2525, or EMAIL_USE_SSL with 465.
ssl.SSLError: wrong version numberPort and flag do not match: EMAIL_USE_SSL on 587 or EMAIL_USE_TLS on 465. Fix the pair.
TimeoutError or the request hangsOutbound 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 sendingEMAIL_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.

SMTP Relay 5K: $5 · 5000SMTP Relay 20K: $15 · 20000SMTP Relay 50K: $30 · 50000SMTP Relay 150K: $60 · 150000
See SMTP relay plans

What you can send: Acceptable Use Policy.