How to add Username in Email from Phoenix Guide

I’ve got email working following the Sending Email with SMTP using Bamboo and the SendGrid adapter (Mailgun didn’t work for me), so that an email is sent once a newly created user signs up for my app.

I’m just getting my head around the basics - so far I can print the current sessions username to the front page of my app once the user is signed in, and am now trying to improve the signup process by sending an account activation email that (when I work out how to do it) that will include an activation URL link.

Before creating the activation link, I’m trying to learn more about assigns by adding the username from the signup form in the welcome.html.eex template like so:

<p>
  <strong>Welcome <%= @username %><strong> to MyApp!
</p>
<p>
  Your email address is <%= @email_address %>
</p>

The email address the user enters in the signup form is being rendered in the email, but I’m struggling to find where and how to assign the username.

My beginner understanding is that assigns are made in controllers or sometimes views(?), so I’ve tried including the User.Controller in the Email controller, and adding an assign to

welcome_html_email("myemail.address")

as well as in

def welcome_html_email(email_address) do (below)

but I’m always getting errors of the kind

welcome_html_email/n is undefined

or

Request: POST /users
** (exit) an exception was raised:
    ** (ArgumentError) assign @username not available in eex template.

Please make sure all proper assigns have been set. If this
is a child template, ensure assigns are given explicitly by
the parent template as they are not automatically forwarded.

Available assigns: [:email_address, :view_module, :view_template]

and the errors often say the User.Controller I try to include is ‘unused’.

Here’s the working bit of my User.Controller that sends creates the new user and sends the email:

defmodule Myapp.UserController do
...
def create(conn, %{"user" => user_params}) do
    changeset = User.changeset(%User{}, user_params)

    case Repo.insert(changeset) do
      {:ok, _user} ->
        conn
        |> put_flash(:info, "Check your email for a link to active your account.")
        |> redirect(to: page_path(conn, :index))
        Mybaseapp.Email.welcome_html_email("myemail.address") |> Mybaseapp.Mailer.deliver_now
      {:error, changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

This is from the Sending Email guide:

defmodule MyApp.Email do
  use Bamboo.Phoenix, view: MyApp.EmailView

  def welcome_text_email(email_address) do
    new_email()
    |> to(email_address)
    |> from("us@example.com")
    |> subject("Welcome!")
    |> put_text_layout({MyApp.LayoutView, "email.text"})
    |> render("welcome.text")
  end

  def welcome_html_email(email_address) do
    email_address
    |> welcome_text_email()
    |> put_html_layout({MyApp.LayoutView, "email.html"})
    |> render("welcome.html", email_address: email_address) # <= Assignments
  end
end

If I try to add a username assigns in

|> render("welcome.html", email_address: email_address)

and in where it is used User.Controller, the error says

welcome_html_email is hidden or private.

2 Likes

Here is an example of a bamboo Email that takes an extra argument:

def registration_email(user, token) do
  base_email()
  |> to(user.email)
  |> subject("Welcome to the App!")
  |> assign(:user, user)
  |> assign(:token, token)
  |> render(:"self_care/welcome")
end

here is how you call it from a controller or a service etc

user
|> UserEmail.registration_email(token)
|> Mailer.deliver_later()

in the template you’d have the user struct and could do something like Hello <%= @user.name %>! as well as extra @token variable.

PS base_email function above takes care of the boilerplate code:

defp base_email do
  new_email()
  |> from(@app_email)
  |> put_header("Reply-To", @app_email)
  |> put_html_layout({App.LayoutView, "email.html"})
  |> put_text_layout({App.LayoutView, "email.text"})
end
6 Likes

Thanks yurko!!

2 Likes