Proca.Service.EmailBackend behaviour (proca v3.4.1)
EmailBackend behaviour specifies what we want to expect from an email backend. We are using Swoosh for sending emails - it is very convenient because it has lots of adapters. However, we also need to be able to work with templates and Swoosh does not have this.
Recipients
Recipients of transaction emails are Supporters, Targets, Users (in case of notifications)
We use Swoosh.Email for passing email data.
We make use of Email fields:
- assigns - to hold merge tag values
- private[:template] - template
- private[:custom_id] - custom_id
- We use local email templates with single-sending
- We support batch sending for Mailjet, SES bulk api is not good.
Templates
- We use a mustache templates stored in proca (email_templates table)
- Or a service-provider template system (for Mailjet)
Sender Domain/Adddress
We assume a sender has email backend with full domain support of their org.from_email address
We can check this on time of setting the backend - querying the domains via API (when available - similar to how we check the template)
We can do from email "spoofing" to use mixed FROM and Reply-To. Eg. A sends via B backend, their from is hello@a.org, the from will be hello+a.org@b.org, with Reply-To hello@a.org.
We can use this also for MTT, but this creates a security risk of spoofing the real users' emails if we don't put username after + (member+marcin@a.org) but just in fromt of the @ (marcin@a.org). This could result into some serious problems, if someone abuses this to impersonate root@a.org, postmaster@a.org, or a legitimate user. Those who will have a dedicated campaign domain might feel in the safe, but imagine someone using this to access DNS provider for the domain... Another solution - if member+marcin@ is not good enought, to use a fixed prefix/postfix like member_marcin@.
Link to this section Summary
Functions
Delivers list of Email-s using EmailTemplate. Uses Org's email service.
Determine the From + Reply to of the email.
Link to this section Callbacks
batch_size()
Specs
batch_size() :: number()
deliver(list, %Proca.Org{})
Specs
deliver( [ %Swoosh.Email{ assigns: term(), attachments: term(), bcc: term(), cc: term(), from: term(), headers: term(), html_body: term(), private: term(), provider_options: term(), reply_to: term(), subject: term(), text_body: term(), to: term() } ], %Proca.Org{ __meta__: term(), action_pages: term(), action_schema_version: term(), campaigns: term(), config: term(), contact_schema: term(), custom_action_confirm: term(), custom_action_deliver: term(), custom_event_deliver: term(), custom_supporter_confirm: term(), detail_backend: term(), detail_backend_id: term(), doi_thank_you: term(), email_backend: term(), email_backend_id: term(), email_from: term(), event_backend: term(), event_backend_id: term(), high_security: term(), id: term(), inserted_at: term(), name: term(), public_keys: term(), push_backend: term(), push_backend_id: term(), services: term(), staffers: term(), storage_backend: term(), storage_backend_id: term(), supporter_confirm: term(), supporter_confirm_template: term(), title: term(), updated_at: term() } ) :: any()
handle_bounce(params)
Specs
handle_event(params)
Specs
list_templates(org)
Specs
list_templates( org :: %Proca.Org{ __meta__: term(), action_pages: term(), action_schema_version: term(), campaigns: term(), config: term(), contact_schema: term(), custom_action_confirm: term(), custom_action_deliver: term(), custom_event_deliver: term(), custom_supporter_confirm: term(), detail_backend: term(), detail_backend_id: term(), doi_thank_you: term(), email_backend: term(), email_backend_id: term(), email_from: term(), event_backend: term(), event_backend_id: term(), high_security: term(), id: term(), inserted_at: term(), name: term(), public_keys: term(), push_backend: term(), push_backend_id: term(), services: term(), staffers: term(), storage_backend: term(), storage_backend_id: term(), supporter_confirm: term(), supporter_confirm_template: term(), title: term(), updated_at: term() } ) :: {:ok, [ %Proca.Service.EmailTemplate{ __meta__: term(), compiled: term(), html: term(), id: term(), locale: term(), name: term(), org: term(), org_id: term(), ref: term(), subject: term(), text: term() } ]} | {:error, reason :: String.t()}
supports_templates?(org)
Specs
supports_templates?( org :: %Proca.Org{ __meta__: term(), action_pages: term(), action_schema_version: term(), campaigns: term(), config: term(), contact_schema: term(), custom_action_confirm: term(), custom_action_deliver: term(), custom_event_deliver: term(), custom_supporter_confirm: term(), detail_backend: term(), detail_backend_id: term(), doi_thank_you: term(), email_backend: term(), email_backend_id: term(), email_from: term(), event_backend: term(), event_backend_id: term(), high_security: term(), id: term(), inserted_at: term(), name: term(), public_keys: term(), push_backend: term(), push_backend_id: term(), services: term(), staffers: term(), storage_backend: term(), storage_backend_id: term(), supporter_confirm: term(), supporter_confirm_template: term(), title: term(), updated_at: term() } ) :: true | false
Link to this section Functions
batch_size(org)
deliver(recipients, org, email_template \\ nil)
Specs
deliver( [ %Swoosh.Email{ assigns: term(), attachments: term(), bcc: term(), cc: term(), from: term(), headers: term(), html_body: term(), private: term(), provider_options: term(), reply_to: term(), subject: term(), text_body: term(), to: term() } ], %Proca.Org{ __meta__: term(), action_pages: term(), action_schema_version: term(), campaigns: term(), config: term(), contact_schema: term(), custom_action_confirm: term(), custom_action_deliver: term(), custom_event_deliver: term(), custom_supporter_confirm: term(), detail_backend: term(), detail_backend_id: term(), doi_thank_you: term(), email_backend: term(), email_backend_id: term(), email_from: term(), event_backend: term(), event_backend_id: term(), high_security: term(), id: term(), inserted_at: term(), name: term(), public_keys: term(), push_backend: term(), push_backend_id: term(), services: term(), staffers: term(), storage_backend: term(), storage_backend_id: term(), supporter_confirm: term(), supporter_confirm_template: term(), title: term(), updated_at: term() }, %Proca.Service.EmailTemplate{ __meta__: term(), compiled: term(), html: term(), id: term(), locale: term(), name: term(), org: term(), org_id: term(), ref: term(), subject: term(), text: term() } | nil ) :: :ok | {:error, [:ok | {:error, String.t()}]}
Delivers list of Email-s using EmailTemplate. Uses Org's email service.
:ok
- all went fine
{:error, [....]}
- there was some error - could be partial!
Surprise: you can get {:error, [:ok, :ok, :ok]}
with there was some error but adapter decided to drop the email (fatal problem, retry will not help)
determine_sender(email, org)
Determine the From + Reply to of the email.
Support these cases:
- No from set, and current org sends - use the org.email_from
- No from set, and org sends via other org - set the orgs FROM, then pass to other clause to get a mixed format
- FROM set, we need to check the address - if email is different then sending one, replace FROM email with a mix.