How to Attach File to Email in Django

2010

Months ago, my team had difficulty attaching files to email in Django 2. It was a web development project for a local church. Church member who wants to be baptized has to submit an online form that includes their identity (name, address, etc) along with birth certificate (called akte lahir) and previous baptize certificate (called surat baptis). Both in pdf format.

Church admins (the deacons) would receive the form data via email.

The problem is we got difficulty attaching the said documents. They were missing / not shown correctly in email.

Consider this model in models.py:

class Katekisan(models.Model):
    """This model represents church member who wants to be baptized."""

    nama = models.CharField('Nama lengkap', max_length=500, help_text='Tanpa singkatan dan gelar.')
    # ..and other fields..
    akte_lahir = models.FileField(upload_to='supporting_documents/', help_text='Format pdf', validators=[FileExtensionValidator(allowed_extensions=['pdf']), file_size_validator])
    surat_baptis = models.FileField(upload_to='supporting_documents/', help_text='Format pdf', validators=[FileExtensionValidator(allowed_extensions=['pdf']), file_size_validator])

    def __str__(self):
        return self.nama

    class Meta:
        ordering = ['-date_created', ]

Note: Katekisan is the church member (requester). The instance could be saved to database with: katekisan = form.save() (we used Django ModelForm based on model above).

Both akte_lahir and surat_baptis are file fields with simple validator. They should be uploaded to '[MEDIA_ROOT]/supporting_documents/'.

And here is the solution to our problem:

In views.py:

# Send email to the office
email = EmailMessage(
    # trimmed for simplicity
    subject='New Request',
    body=render_to_string('form.html', {
        'kat': katekisan,
    }),
    from_email=from_email,
    to=to,
    reply_to=[katekisan.email, ],
)
email.content_subtype = 'html'
# attach pdfs
email.attach_file(os.path.join(settings.MEDIA_ROOT, katekisan.akte_lahir.name))
email.attach_file(os.path.join(settings.MEDIA_ROOT, katekisan.surat_baptis.name))
email.send()

Notice the email.attach_file() part. To select the file (after uploading it before), we used os.path.join() to concatenate MEDIA_ROOT directory and the file names (.name). We didn't use .url. Also see the official Django docs.

Now when our deacon receives the email, he can easily download the PDFs attached at the end of the email :-)