---
# System prepended metadata

title: 1952 Celery Email Queue Plan of Attack

---

# 1952 Celery Email Queue Plan of Attack

## Description
In order to send emails from our app we want to use a celary task to handle emails asyncronously. When an email is created it will be put into a queue where celery will pull from.

## Approaches
Options 1 and 2 are the main approaches. 3 and 4 are optional add ons.

### 1: Simplest backend solution using a function
There will be a new folder called `email`. It wont even be a django app. There will be a shared task celery function that takes the variables required to send an email. That function will construct the email and send it using django's email server.

When an email needs to be sent this function will be imported and called. No queue is needed because celery will spawn a new broker(Im not sure if celery works this way with shared tasks. A Queue might actually be needed.)

If new ways to send emails are required, like sending emails to django admins, a new function can be created.

**Potential problems:** 
1. I am not sure if celery can use django dependencies like `django.core.mail`.
2. It might be messy to extend.  
3. If celery cannot spawn infinite brokers this approach wont work.
4. If celery can spawn infite workers there might be memory problems.


### 2: More robust class based backend approach

An email class will be used so multiple versions of it can be spawned, or so it can hold state, like a queue. 

The benefits of this, as opposed to just keeping track of a queue object, is that it makes it easier to construct an email, or group of emails, over time. This will be useful if we want to construct multiple emails then use django's batch email function to send them all at once.

This also follows a more familiar OOP approach and makes it easy to write new functions for the email class.

The email class would maintain the queue and the shared celery task would pull from that queue.

To use this class it would be imported, instantiated, then various functions would be called to handle the email work flow.

Functions include:
* validate email
* construct email
* send email (celery shared task)
* create batch email (optional)
* send batch email (optional)
* create django admin email (optional)
* send django admin email (optional)
    
### Potential problems:
1. Over engineered, not everything needs to be object orriented and we probably wont need to instantiate multiple version of this class sense it has asyncrounous functionality with celery.


## 3. Fancier version of 2 using redis

All the same as option 2 but we use Redis instead of a python queue.

### Potential problems:
1. Over engineered. Not sure there is any reason to use redis here? It would be good to know an estimate of the max number of emails that could be sent at a time. Maybe redis would be important since the app has peak usage at the end of each financial quarter.


## 4. Frontend and backend approach

This could be added to any of the previous options. Make a new Django app that has a view and urls. The main purpose here would be to have that url that could be used to trigger the sending of an email. This could keep the backend logic cleaner.

If an email needs to be created by a user(now or in the future) then it would be cleaner to have a separate email view in the email app.

If something like this is needed in the future we can implement it now, but just not add the view or urls until we need them.

### Potential problems:
1. If there is a url route that triggers the creation or sending of an email, extra validation steps will be needed.


## Cameron's initial recomendation
My suggestion is to use option 2 as it will be the easiest to extend and understand. Potentially 3 and 4 could be added. 

I don't think we will need Redis for this. A python queue will be a good start and can be replaced by redis later.

The ticket says we decided not to use a django view. If we do anticipate that a user will need to construct an email message from the frontend, or that we want to trigger email functionality from the frontend or API, then we should build this as a django app even if we dont use the views, urls, and everything else that comes with a django app.

Option 1 could be simpler, but being a more functional approach it could get confusing as this is extended.