@@ -32,7 +32,8 @@ defmodule SendGrid.Email do
3232 custom_args: nil ,
3333 send_at: nil ,
3434 headers: nil ,
35- attachments: nil
35+ attachments: nil ,
36+ __phoenix_view__: nil
3637
3738
3839 @ type t :: % Email { to: nil | [ recipient ] ,
@@ -47,7 +48,8 @@ defmodule SendGrid.Email do
4748 custom_args: nil | custom_args ,
4849 send_at: nil | integer ,
4950 headers: nil | [ header ] ,
50- attachments: nil | [ attachment ] }
51+ attachments: nil | [ attachment ] ,
52+ __phoenix_view__: nil | atom }
5153
5254 @ type recipient :: % { email: String . t , name: String . t | nil }
5355 @ type content :: % { type: String . t , value: String . t }
@@ -340,4 +342,104 @@ defmodule SendGrid.Email do
340342 defp add_address_to_list ( list , email , name ) when is_list ( list ) do
341343 list ++ [ address ( email , name ) ]
342344 end
345+
346+ @ doc """
347+ Sets the Phoenix View to use.
348+
349+ This will override the default Phoenix View if set in under the `:phoenix_view`
350+ config value.
351+
352+ ## Examples
353+
354+ Email.put_phoenix_view(email, MyApp.Web.EmailView)
355+
356+ """
357+ @ spec put_phoenix_view ( t , atom ) :: t
358+ def put_phoenix_view ( % Email { } = email , module ) when is_atom ( module ) do
359+ % Email { email | __phoenix_view__: module }
360+ end
361+
362+ @ doc """
363+ Renders the Phoenix template with the given assigns.
364+
365+ You can set the default Phoenix View to use for your templates by setting the `:phoenix_view` config value.
366+ Additionally, you can set the view on a per email basis by calling `put_phoenix_view/2`.
367+
368+ ## Explicit Template Extensions
369+
370+ You can provide a template name with an explicit extension such as `"some_template.html"` or
371+ `"some_template.txt"`. This is set the content of the email respective to the content type of
372+ the template rendered. For example, if you render an HTML template, the output of the rendering
373+ will be the HTML content of the email.
374+
375+ ## Implicit Template Extensions
376+
377+ You can omit a template's extension and attempt to have both a text template and HTML template
378+ rendered. To have both types rendered, both templates must share the same base file name. For
379+ example, if you have a template named `"some_template.txt"` and a template named `"some_template.html"`
380+ and you call `put_phoenix_template(email, "some_template")`, both templates will be used and will
381+ set the email content for both content types. The only caveat is *both files must exist*, otherwise you'll
382+ have an exception raised.
383+
384+ ## Examples
385+
386+ iex> Email.put_phoenix_template(email, "some_template.html")
387+ %Email{content: [%{type: "text/html", value: ...}], ...}
388+
389+ iex> Email.put_phoenix_template(email, "some_template.txt", name: "John Doe")
390+ %Email{content: [%{type: "text/plain", value: ...}], ...}
391+
392+ iex> Email.put_phoenix_template(email, "some_template", user: user)
393+ %Email{content: [%{type: "text/plain", value: ...}, %{type: "text/html", value: ...}], ...}
394+
395+ """
396+ @ spec put_phoenix_template ( t , String . t , [ ] ) :: t
397+ def put_phoenix_template ( % Email { } = email , template_name , assigns \\ [ ] ) do
398+ with true <- ensure_phoenix_loaded ( ) ,
399+ view_mod <- phoenix_view_module ( email ) do
400+ case Path . extname ( template_name ) do
401+ ".html" ->
402+ render_html ( email , view_mod , template_name , assigns )
403+ ".txt" ->
404+ render_text ( email , view_mod , template_name , assigns )
405+ _ ->
406+ email
407+ |> render_html ( view_mod , template_name <> ".html" , assigns )
408+ |> render_text ( view_mod , template_name <> ".txt" , assigns )
409+ end
410+ end
411+ end
412+
413+ defp render_html ( email , view_mod , template_name , assigns ) do
414+ html = Phoenix.View . render_to_string ( view_mod , template_name , assigns )
415+ put_html ( email , html )
416+ end
417+
418+ defp render_text ( email , view_mod , template_name , assigns ) do
419+ text = Phoenix.View . render_to_string ( view_mod , template_name , assigns )
420+ put_text ( email , text )
421+ end
422+
423+ defp ensure_phoenix_loaded do
424+ unless Code . ensure_loaded? ( Phoenix ) do
425+ raise ArgumentError , "Attempted to call function that depends on Phoenix. " <>
426+ "Make sure Phoenix is part of your dependencies"
427+ end
428+ true
429+ end
430+
431+ defp phoenix_view_module ( % Email { __phoenix_view__: nil } ) do
432+ mod = config ( :phoenix_view )
433+ unless mod do
434+ raise ArgumentError , "Phoenix view is expected to be set or configured. " <>
435+ "Ensure your config for :sendgrid includes a value for :phoenix_view or" <>
436+ "explicity set the Phoenix view with `put_phoenix_view/2`."
437+ end
438+ mod
439+ end
440+ defp phoenix_view_module ( % Email { __phoenix_view__: view_module } ) , do: view_module
441+
442+ defp config ( key ) do
443+ Application . get_env ( :sendgrid , key )
444+ end
343445end
0 commit comments