Handle emails properly in phoenix


I’m wondering how to handle emails properly in a phoenix application. There doesn’t appear to be a standard way of doing this, which surprises me.

Coming from the Rails world, my first intention is to bind transaction emails to data actions.

Eg. A Model can be submitted, and this action triggers a ModelEmail.submitted(query).

But if I want to call Model.submit(model) in a console where only the Repo context is Loaded, not the Endpoint, I get:

** (ArgumentError) argument error
    (stdlib) :ets.lookup(MyApp.Endpoint, :__phoenix_url__)
    (phoenix) lib/phoenix/config.ex:42: Phoenix.Config.cache/3
    (vae) web/router.ex:1: MyApp.Router.Helpers.application_url/4
    (vae) web/emails/model_email.ex:83: MyApp.ModelEmail.submit/1

because the email makes the use of the Endpoint to get absolute URLs in the email: Routes.model_url(Endpoint, :show, model)

So how should this be done?

IMHO, Sending email should be independent from starting the server, as the only necessary thing is the base URL.

Shouldn’t emails be in a separate process, which can be initialized if desired, and which will receive, either a conn, or an Enpoint or eventually a string like https://example.com so that paths like /path are turned into https://example.com/path?

What are the best practices here? I guess I’m not the first one to have this issue…

Route helpers also work with %URI{} structs.

1 Like


Upping it here, I still have issues.

Though I successfully use:

MyAppWeb.Router.Helpers.root_url(struct(URI, Application.get_env(:my_app, MyAppWeb.Endpoint)[:url]), :index)

The same with static_url doesn’t :frowning:

> MyAppWeb.Router.Helpers.static_url(struct(URI, Application.get_env(:my_app, MyAppWeb.Endpoint)[:url]), :index)

** (FunctionClauseError) no function clause matching in MyAppWeb.Router.Helpers.static_url/2    
    The following arguments were given to MyAppWeb.Router.Helpers.static_url/2:
        # 1
          authority: nil,
          fragment: nil,
          host: "localhost",
          path: nil,
          port: 80,
          query: nil,
          scheme: "http",
          userinfo: nil
        # 2
    Attempted function clauses (showing 3 out of 3):
        def static_url(%Plug.Conn{private: private}, path)
        def static_url(%_{endpoint: endpoint} = conn, path)
        def static_url(endpoint, path) when is_atom(endpoint)
    (my_app) lib/my_app_web/router.ex:1: MyAppWeb.Router.Helpers.static_url/2
    (my_app) lib/my_app_web/emails/job_seeker_email.ex:51: MyAppWeb.UserEmail.campaign/2

Any idea why and how to add images in my email contents?