Repository: DjangoGirls/djangogirls

Issue:
"Access to Django Girls website" HTML email sent as plain text
I've received the "Access to Django Girls website" from hello@djangogirls.org to get the access details of the new event's website.

This email is HTML, but it is displayed as plain text:

``` html
<p>Hi there!</p>

<p>Congrats! You're now a Django Girls organizer, so awesome! Here is access to your
website:</p>

[...]
```

Looking at the email's body, it is sent with `Content-Type: text/plain; charset=utf-8` which I think would be the cause of the issue.

Looking at the site's codebase, I think this is where the problem is: https://github.com/DjangoGirls/djangogirls/blob/8da41d3303d4bde4488f22129e1cd3905b2d36f5/core/forms.py#L66 

``` python
    def notify_new_user(self, user):
        content = render_to_string('emails/new_user.html', {
            'user': user,
            'event': self.cleaned_data['event'],
            'password': self._password,
            'errors': self._errors,
        })
        subject = 'Access to Django Girls website'
        self.send_email(content, subject, user)

    def send_email(self, content, subject, user):
        send_mail(subject, content, "Django Girls <hello@djangogirls.org>",
                  [user.email])
```

The email content is rendered from HTML templates, but is sent with `send_mail`'s `message` instead of `html_message`. See https://docs.djangoproject.com/en/1.10/topics/email/#send-mail.



Discussion:

Resolving patch:
diff --git a/core/forms.py b/core/forms.py
--- a/core/forms.py
+++ b/core/forms.py
@@ -2,8 +2,9 @@
 from django import forms
 from django.conf import settings
 from django.contrib.auth import forms as auth_forms
-from django.core.mail import send_mail
 from django.template.loader import render_to_string
+from django.core.mail import EmailMessage
+from captcha.fields import ReCaptchaField
 from slacker import Error as SlackerError
 
 from core.models import ContactEmail, Event, User
@@ -12,6 +13,7 @@
 
 class BetterReCaptchaField(ReCaptchaField):
     """A ReCaptchaField that always works in DEBUG mode"""
+
     def clean(self, values):
         if settings.DEBUG:
             return values[0]
@@ -42,7 +44,8 @@ def invite_to_slack(self, email, name):
         try:
             user_invite(email, name)
         except (ConnectionError, SlackerError) as e:
-            self._errors.append('Slack invite unsuccessful, reason: {}'.format(e))
+            self._errors.append(
+                'Slack invite unsuccessful, reason: {}'.format(e))
 
     def notify_existing_user(self, user):
         content = render_to_string('emails/existing_user.html', {
@@ -63,8 +66,12 @@ def notify_new_user(self, user):
         self.send_email(content, subject, user)
 
     def send_email(self, content, subject, user):
-        send_mail(subject, content, "Django Girls <hello@djangogirls.org>",
-                  [user.email])
+        msg = EmailMessage(subject,
+                           content,
+                           "Django Girls <hello@djangogirls.org>",
+                           [user.email])
+        msg.content_subtype = "html"
+        msg.send()
 
     def save(self, *args, **kwargs):
         assert self.is_valid()
@@ -77,7 +84,8 @@ def save(self, *args, **kwargs):
         if created:
             self._password = User.objects.make_random_password()
             user.first_name = self.cleaned_data['name'].split(' ')[0]
-            user.last_name = self.cleaned_data['name'].replace(user.first_name, '')
+            user.last_name = self.cleaned_data[
+                'name'].replace(user.first_name, '')
             user.is_staff = True
             user.is_active = True
             user.set_password(self._password)
@@ -152,6 +160,7 @@ class Meta:
 
 
 class EventChoiceField(forms.ModelChoiceField):
+
     def label_from_instance(self, obj):
         return "{}, {}".format(obj.city, obj.country)
 


Test patch: