Enviar correos electrónicos por SMTP+TLS con python

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.

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *

Aquest lloc utilitza Akismet per reduir els comentaris brossa. Apreneu com es processen les dades dels comentaris.