Package: email-verify
email-verifySee it on:GitHub|PyPIA lightweight Django app for adding user email verification at registration.contentsfeaturessetupusagemixin and decoratorcustom redirections and template overridingcustom email subject, body and senderproviding the domain to the email functionknown issue with domain retrievalchangelog:v0.1.5v0.1.4v0.1.3v0.1.2v0.1.1featuresEasy integration with any Django appDesigned the Django way - offers granular customization alongside default behaviorWorks out-of-the-box with Django's SMTP backend. Can be customized to work with any backend.getting startedsetupInstall it with:pip install email-verifyIf you're using virtual environments, make sure to activate it before running this commandAddemail_verifyto yourINSTALLED_APPSlist, after your main app. Your INSTALLED_APPS should look similar to this:# settings.py:INSTALLED_APPS=['your_main_app','email_verify','django.contrib.admin',# ...]Include the url conf of email-verify in your project's (not your app's) url configuration, after your other url confs.# urls.pyurlpatterns=[path('admin/',admin.site.urls),path('',include('your/main/app.urls')),# ...path('where/you/want/',include('email_verify.urls')),]Once you add the app to your INSTALLED_APPS, you might notice you have a new migration available. email-verify establishes a one-to-one relation with the built-in User model (from django.contrib.auth.models).You can apply migrations via:python manage.py migrateSetting up default send function:email-verify is designed work out-of-the-box with Django's SMTP backend. If you want to keep to defaults, make sure to add the following configuration to your settings (assuming the hostname, host user and password are kept in environment variables):EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend'EMAIL_HOST=os.environ.get('EMAIL_HOST')EMAIL_PORT=587# or any other SMTP port your host is configured towardsEMAIL_HOST_USER=os.environ.get('EMAIL_HOST_USER')EMAIL_HOST_PASSWORD=os.environ.get('EMAIL_HOST_PASSWORD')EMAIL_USE_TLS=True# or False, depending on your host configurationThe above is the standard configuration for Django's SMTP backend.Providing a custom send function:If you don't want to use Django's default SMTP backend or have a specific function you'd rather use, provide the function inEMAIL_VERIFY_SEND_FUNCin yoursettings.py. The function provided should accept 2 arguments: user and verification_link. You can access user's e-mail throughuser.email.Below is an example for a custom emailing function. In this example, instead of actually sending an email, we print the token on the console (useful during dev):# custom email function example:# define a custom functiondefcustom_send_email(user,verification_link):print(verification_link)# settings.py# set EMAIL_VERIFY_SEND_FUNC to your custom functionEMAIL_VERIFY_SEND_FUNC=custom_send_emailusageemail-verify creates a one-to-one relation with the built-in User model. Every time a new User is created and saved, email-verify will create a new EmailVerification record with is_verified set to false. On its own this has no effect on your project, except modifying your User model with an EmailVerification relation.If you're usingUserCreationFormyou can instead useEmailValidationUserCreationfor exposing email on sign-up. IfEMAIL_VERIFY_ENFORCE_UNIQUE_EMAILSisTrue(default) a signal will trigger pre_save, and will throw adjango.core.exceptions.ValidationError. This will not be handled by the Form, as it only checks for email validity and non-emptiness.If your SMTP configuration or custom emailing function is setup correctly, an email message will be delivered to the address used at registration as soon as a user registers. Lookout for customEmailSendingExceptionon user.save(). No silent errors.By default the following urlpattern will be used for the verification endpoint:verify_email/<str:token>/If you want to use another endpoint for verification, be sure to set it up in your projects's url conf before including email_verify's url conf. Customized url pattern must have a<str:token>.The token is cryptographically signed using `itsdangerous` package. Message includes the user's id, current domain/host and a timestamp. The domain is not used for verification if `DEBUG=True` in `settings.py`, but in production, it checks against `ALLOWED_HOSTS` and will reject the token if the domain value is not found within the list. The timestamp is used to check against `EMAIL_VERIFY_EXPIRES_IN` (defaults to 3600 seconds) value to consider the token expired. If this value is not positive, the token won't expire.mixin and decoratorTo restrict access to unverified users, you may decorate your view functions with@user_verifiedfromemail_verify.decorators, or you may useEmailVerificationMixinfromemail_verify.mixinsfor your class-based views. In either case,is_authenticatedis checked internally, so you wouldn't need@require_loginorLoginRequiredMixinon-top.custom redirections and template overridingThere are several ways you can customizeemail-verify. You can bypass all view functionality by urlconf, as all logic is handled by signals during.save()calls. You can provide redirect urls toEmailVerificationViewforsuccess_urlandfailure_url, or you can overwrite the default templates attemplates/email_verify/success.htmlandtemplates/email_verify/failure.html. For failure rendering,EmailVerificationViewwill provide an error message in context:message. For success rendering, it will provide amain_pagewhich can be provided viaMAIN_PAGEin settings.py (default'/') which will provide a link to your home page for the default success template.custom email subject, body and senderCustomize your subject field by providingEMAIL_VERIFY_SUBJECT_LINEin settings.py
You can also customize the body of your email. Be sure to:Include the verification link via$:_VERIFICATION_LINKmagic string somewhereIf you provideEMAIL_VERIFY_HTML_MESSAGEalso provideEMAIL_VERIFY_TEXT_MESSAGEas a fallback.
You can change the sender email viaEMAIL_VERIFY_FROM_ADDRESSproviding the domain to the email functionThe function(s) used for sending emails can be accessed atemail_verify.email_utils. You may want to use these functions manually in your workflow.send_verification_email(user, send_email_func, request=None)requires the current domain to be signed with the token and will try to retrieve it using the following code-block. Depending on where you call this function, you may want to pass arequestobject to it. Explicit passing of a domain/host name was abandoned in favor of user-friendliness (optionaldomainkeyword is added in 0.1.5, which will bypass the following code block if provided):# Use the request object if provided, otherwise fall back to ALLOWED_HOSTSifrequest:current_site=get_current_site(request)domain=current_site.domainport=request.get_port()ifportnotin('80','443'):domain+=f":{port}"else:ifsettings.DEBUG:domain=settings.ALLOWED_HOSTS[0]ifsettings.ALLOWED_HOSTSelse'localhost'domain='localhost'ifdomain=='*'elsedomainport=settings.DEBUG_PORTifhasattr(settings,'DEBUG_PORT')else'8000'domain+=f":{port}"elifsettings.ALLOWED_HOSTS:domain=settings.ALLOWED_HOSTS[0]else:raiseInvalidDomainException("Couldn't resolve domain for token. If DEBUG is set to False ALLOWED_HOSTS[0] must be set or request object should be passed to function send_verification_email")Be sure to set aDEBUG_PORTduring development if you're using another port than8000(i.e. running multiple Django servers).If you're using non-http and non-https ports in production, in order for a valid verification URL to be generated you should either pass in arequestobject, or adomainstring withdomain:portformatting.known issue with domain retrieval:If you're usingdjango_on_heroku, theALLOWED_HOSTS=['*']overwrite is breaking. You can either disable the allowed_hosts modification ofdjango_on_herokuor (added in 0.1.6) provide a host viaEMAIL_VERIFY_ALLOWED_HOSTliteral insettings.pywhichemail_verify.utils.verify_tokenwill use to check against the unsigned token's domain. You will still have to provide a request object or a domain string to the downstream functions to correctly get a domain for signing. You can provide a string inEMAIL_VERIFY_USE_DOMAINliteral to coerce internal functions to use the given domain. This will take precedence over all other methods except providing a domain to the functions directly.Changelogv0.1.10 (hotfix)Broken username fixv0.1.9 (hotfix)Broken domain verification logic fixv0.1.8 (hotfix)0.1.7 did not work as intendedv0.1.7 (hotfix)If username field exists, set ordering to show it on top.v0.1.6Decouple logic from built-in User model. Instead ofUseruseget_user_model()for cases where a custom user model is used.Add a workaround forALLOWED_HOSTS* overwrites. IntroducedEMAIL_VERIFY_ALLOWED_HOSTandEMAIL_VERIFY_USE_DOMAINAddtests.pyEmailVerificationUserCreationFormnow only exposesemailfield. Checks if theAUTH_USER_MODELhas a username field before attempting to expose it.v0.1.5Documentation updateAddeddomainas an optional argument tosend_verification_emailand its wrappers for bypassing domain retrieval logic and providing the domain directly.v0.1.4Feature: If existing users without e-mails access a@user_verifieddecorated view orUserVerifiedMixinCBV, they will get a 404 instead of rising an error.v0.1.3AddUserVerifiedMixinv0.1.2 (hotfix)Bugfix: e-mail uniqueness not enforced if email is emptyv0.1.1Introduced email uniqueness enforcingDecoupled emailing logic from Form and Views, email is sent via Signal receiver at time of creationEnhanced model:Removedverified_by_adminAddedemail_sent_status,last_email_date,verified_datefieldsRemoved admin site registrationCustom form no longer redirectsRemoved ***_TEMPLATE_NAME patternRemoved templates, urlconfs and views pertaining to email sending statusAddedEmailSendingExceptionwhich can be used to handle email sending status by the userConvertedemail_verify:verify_emailto CBV. Uses success and failure redirections with failure message as query parameter.Removedis_validoverwrite to useclean_email, in-line with Django's built-in validation mechanisms.