Pues otra espinita que llevaba unos días clavada sacada! :)
Con uno de los programas que estoy haciendo necesitaba mandar un correo electrónico para hacer la verificación de correo electrónico y activación posterior del usuario. Me puse con ello pero los ejemplos que encontraba requería poner la configuración del correo electrónico en el código en lugar de cogerlo de la base de datos, además estaba dando problemas de autenticación con el servidor, cosa que entre que mi código estaba mal y la configuración con el servidor era errónea no se mandaban los mensajes, en el servidor salía el error feúcho:
Error: dict-client: server returned failure:
Así que para implementar ésto sólo vamos a tocar los ficheros de mi proyecto almacenado en ~/dev/ (mi entorno de desarrollo, en producción lo suelo dejar bajo /var/www/ o /var/www/html/).
en ~/dev/capa8/ es donde almaceno los settings.py y las url.py
en ~/dev/web/ es donde almaceno el código de mi programa
~/dev/ es pues donde está mi manage.py de django
Vamos a ver pues el código de urls.py almacenado en capa8, vamos a ver la página de registro de usuario y de validación del correo electrónico:
# vi capa8/urls.py ############ # /account/ # account patterns urlpatterns += [ ... path('create', views_account.create, name='create'), path('verify/<str:token>', views_account.verify_mail, name='verify'), ... ]
Ambas funciones las vamos a buscar en el fichero que está en web/views_account.py, pero primero editaremos el web/views.py que es donde voy a crear la función a la que le pasaremos la dirección donde queremos enviar el correo, el asunto y el mensaje y va a mandar el correo electrónico recogiendo los datos de la base de datos.
# vi web/views.py from django.contrib.auth.decorators import user_passes_test @user_passes_test(lambda u: u.is_authenticated) def send_email_tls(request, to, subject, message): import smtplib, ssl smtp_server = str(Config.objects.get(name='smtp.host')) port = str(Config.objects.get(name='smtp.port')) # For starttls sender_email = str(Config.objects.get(name='smtp.username')) password = str(Config.objects.get(name='smtp.password')) from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText msg = MIMEMultipart('alternative') msg['From'] = sender_email msg['To'] = to msg['Subject'] = subject html_message = MIMEText(message, "html") msg.attach(html_message) context = ssl.create_default_context() # Try to log in to server and send email try: server = smtplib.SMTP(smtp_server,port) server.starttls(context=context) # Secure the connection server.login(sender_email, password) server.sendmail(sender_email, to, msg.as_string().encode('utf-8')) except Exception as e: # Print any error messages to stdout print(e) finally: server.quit()
Luego en web/views_account.py en la sección que recibimos la respuesta POST de la creación del usuario, llamamos la función que acabamos de crear en views.py
# vi web/views_account.py # token from django.utils.crypto import get_random_string _token = get_random_string(32, allowed_chars='abcdefghijklmnopqrstuvwxyz0123456789') Profile.objects.filter(user=request.user.id).update(name1=username) Profile.objects.filter(user=request.user.id).update(email=email) Profile.objects.filter(user=request.user.id).update(token=_token) _hostname = str(Config.objects.get(name='core.hostname')) to = email subject = "Wireguard Capa8.net - Confirm e-mail" message = """ Thanks for registering to wireguard Capa8.net Service, to activate your account you must verify this e-mail. Navigate to next link to activate your account and configure your peer to your cell phone or computer: <a href="https://" ""="" +="" _hostname="" """="" verify="" _token="" """"="">https://""" + _hostname + """/verify/""" + _token + """</a> Thanks you much! :) <strong>Capa8 Team</strong> <a mailto:"info@capa8.net">info@capa8.net</a> """ views_account.send_email_tls(request, to, subject, message) logout(request) _return = views.index(request) return _return
Ahora en la parte de verificar el correo electrónico, en el mismo fichero web/views_account.py que es donde almaceno todo el código referente a la gestión de los usuarios.
# vi web/views_account.py def verify_mail(request, token): if Profile.objects.filter(token=token).filter(user_status='new').count() == 1: Profile.objects.filter(token=token).update(user_status='active') _user = Profile.objects.filter(token=token) return views.index(request)
Si el usuario está en estado nuevo en mi modelo Profile y el token es correcto, entonces activará el usuario sin hacer login, así que el usuario tendrá que introducir sus datos.