/src/smtp/z_email.erl

http://github.com/zotonic/zotonic · Erlang · 233 lines · 161 code · 35 blank · 37 comment · 2 complexity · 5cd22744226da83242e4bf8793a15e08 MD5 · raw file

  1. %% @author Marc Worrell <marc@worrell.nl>
  2. %% @copyright 2009-2011 Marc Worrell
  3. %% Date: 2009-11-02
  4. %%
  5. %% @doc Send e-mail to a recipient. Optionally queue low priority messages.
  6. %% Copyright 2009-2011 Marc Worrell
  7. %%
  8. %% Licensed under the Apache License, Version 2.0 (the "License");
  9. %% you may not use this file except in compliance with the License.
  10. %% You may obtain a copy of the License at
  11. %%
  12. %% http://www.apache.org/licenses/LICENSE-2.0
  13. %%
  14. %% Unless required by applicable law or agreed to in writing, software
  15. %% distributed under the License is distributed on an "AS IS" BASIS,
  16. %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. %% See the License for the specific language governing permissions and
  18. %% limitations under the License.
  19. -module(z_email).
  20. -author("Marc Worrell <marc@worrell.nl>").
  21. %% interface functions
  22. -export([
  23. email_domain/1,
  24. ensure_domain/2,
  25. bounce_domain/1,
  26. get_admin_email/1,
  27. send_admin/3,
  28. send_page/3,
  29. send/2,
  30. send/3,
  31. send/4,
  32. send_render/4,
  33. send_render/5,
  34. sendq/4,
  35. sendq_render/4,
  36. sendq_render/5,
  37. split_name_email/1,
  38. combine_name_email/2
  39. ]).
  40. -include_lib("zotonic.hrl").
  41. -define(EMAIL_SRV, z_email_server).
  42. % The email domain depends on the site sending the e-mail
  43. email_domain(Context) ->
  44. case m_config:get_value(site, smtphost, Context) of
  45. undefined -> z_context:hostname(Context);
  46. SmtpHost -> z_convert:to_list(SmtpHost)
  47. end.
  48. % Ensure that the sites's domain is attached to the email address.
  49. ensure_domain(Email, Context) when is_list(Email) ->
  50. case lists:member($@, Email) of
  51. true -> Email;
  52. false -> Email ++ [$@|email_domain(Context)]
  53. end;
  54. ensure_domain(Email, Context) ->
  55. ensure_domain(z_convert:to_list(Email), Context).
  56. % Bounces can be forced to a different e-mail server altogether
  57. bounce_domain(Context) ->
  58. case z_config:get('smtp_bounce_domain') of
  59. undefined -> email_domain(Context);
  60. BounceDomain -> BounceDomain
  61. end.
  62. %% @doc Fetch the e-mail address of the site administrator
  63. get_admin_email(Context) ->
  64. case m_config:get_value(zotonic, admin_email, Context) of
  65. undefined ->
  66. case m_site:get(admin_email, Context) of
  67. undefined ->
  68. case m_rsc:p_no_acl(1, email_raw, Context) of
  69. Empty when Empty == undefined orelse Empty == <<>> ->
  70. hd(string:tokens("wwwadmin@" ++ z_convert:to_list(m_site:get(hostname, Context)), ":"));
  71. Email -> Email
  72. end;
  73. Email -> Email
  74. end;
  75. Email -> Email
  76. end.
  77. %% @doc Send a simple text message to the administrator
  78. send_admin(Subject, Message, Context) ->
  79. case get_admin_email(Context) of
  80. undefined ->
  81. {error, no_admin_email};
  82. Email ->
  83. Subject1 = [
  84. $[,
  85. z_context:hostname(Context),
  86. "] ",
  87. Subject
  88. ],
  89. Message1 = [
  90. Message,
  91. "\n\n-- \nYou receive this e-mail because you are registered as the admin of the site ",
  92. z_context:abs_url("/", Context)
  93. ],
  94. z_email_server:send(#email{queue=false, to=Email, subject=Subject1, text=Message1}, Context)
  95. end.
  96. %% @doc Send a page to an e-mail address, assumes the correct template "mailing_page.tpl" is available.
  97. %% Defaults for these pages are supplied by mod_mailinglist.
  98. send_page(undefined, _Id, _Context) ->
  99. {error, not_email};
  100. send_page(_Email, undefined, _Context) ->
  101. {error, not_found};
  102. send_page(Email, Id, Context) when is_integer(Id) ->
  103. Vars = [
  104. {id, Id},
  105. {recipient, Email}
  106. ],
  107. case m_rsc:is_a(Id, document, Context) of
  108. false ->
  109. send_render(Email, {cat, "mailing_page.tpl"}, Vars, Context);
  110. true ->
  111. E = #email{
  112. to=Email,
  113. html_tpl={cat, "mailing_page.tpl"},
  114. vars=Vars,
  115. attachments=[Id]
  116. },
  117. send(E, Context)
  118. end;
  119. send_page(Email, Id, Context) ->
  120. send_page(Email, m_rsc:rid(Id, Context), Context).
  121. %% @doc Send an email message defined by the email record.
  122. send(#email{} = Email, Context) ->
  123. z_email_server:send(Email, Context).
  124. send(MsgId, #email{} = Email, Context) ->
  125. z_email_server:send(MsgId, Email, Context).
  126. %% @doc Send a simple text message to an email address
  127. send(To, Subject, Message, Context) ->
  128. z_email_server:send(#email{queue=false, to=To, subject=Subject, text=Message}, Context).
  129. %% @doc Queue a simple text message to an email address
  130. sendq(To, Subject, Message, Context) ->
  131. z_email_server:send(#email{queue=true, to=To, subject=Subject, text=Message}, Context).
  132. %% @doc Send a html message to an email address, render the message using a template.
  133. send_render(To, HtmlTemplate, Vars, Context) ->
  134. send_render(To, HtmlTemplate, undefined, Vars, Context).
  135. %% @doc Send a html and text message to an email address, render the message using two templates.
  136. send_render(To, HtmlTemplate, TextTemplate, Vars, Context) ->
  137. z_email_server:send(#email{queue=false, to=To, from=proplists:get_value(email_from, Vars),
  138. html_tpl=HtmlTemplate, text_tpl=TextTemplate, vars=Vars}, Context).
  139. %% @doc Queue a html message to an email address, render the message using a template.
  140. sendq_render(To, HtmlTemplate, Vars, Context) ->
  141. sendq_render(To, HtmlTemplate, undefined, Vars, Context).
  142. %% @doc Queue a html and text message to an email address, render the message using two templates.
  143. sendq_render(To, HtmlTemplate, TextTemplate, Vars, Context) ->
  144. z_email_server:send(#email{queue=true, to=To, from=proplists:get_value(email_from, Vars),
  145. html_tpl=HtmlTemplate, text_tpl=TextTemplate, vars=Vars}, Context).
  146. %% @doc Combine a name and an email address to the format `jan janssen <jan@example.com>'
  147. combine_name_email(Name, Email) ->
  148. Name1 = z_convert:to_list(Name),
  149. Email1 = z_convert:to_list(Email),
  150. case Name1 of
  151. [] -> Email1;
  152. _ -> [$"|rfc2047:encode(filter_name(Name1))] ++ "\" <" ++ Email1 ++ ">"
  153. end.
  154. filter_name(Name) ->
  155. filter_name(Name, []).
  156. filter_name([], Acc) ->
  157. lists:reverse(Acc);
  158. filter_name([$"|T], Acc) ->
  159. filter_name(T, [32|Acc]);
  160. filter_name([$<|T], Acc) ->
  161. filter_name(T, [32|Acc]);
  162. filter_name([H|T], Acc) when H < 32 ->
  163. filter_name(T, [32|Acc]);
  164. filter_name([H|T], Acc) ->
  165. filter_name(T, [H|Acc]).
  166. %% @doc Split the name and email from the format `jan janssen <jan@example.com>'
  167. split_name_email(Email) ->
  168. Email1 = string:strip(rfc2047:decode(Email)),
  169. case split_ne(Email1, in_name, [], []) of
  170. {ends_in_name, E} ->
  171. % Only e-mail
  172. {[], z_string:trim(E)};
  173. {N, E} ->
  174. % E-mail and name
  175. {z_string:trim(N), z_string:trim(E)}
  176. end.
  177. split_ne([], in_name, [], Acc) ->
  178. {ends_in_name, lists:reverse(Acc)};
  179. split_ne([], in_qname, [], Acc) ->
  180. {ends_in_name, lists:reverse(Acc)};
  181. split_ne([], to_email, [], Acc) ->
  182. {ends_in_name, lists:reverse(Acc)};
  183. split_ne([], _, Name, Acc) ->
  184. {Name, lists:reverse(Acc)};
  185. split_ne([$<|T], to_email, Name, Acc) ->
  186. split_ne(T, in_email, Name++lists:reverse(Acc), []);
  187. split_ne([$<|T], in_name, Name, Acc) ->
  188. split_ne(T, in_email, Name++lists:reverse(Acc), []);
  189. split_ne([$>|_], in_email, Name, Acc) ->
  190. {Name, lists:reverse(Acc)};
  191. split_ne([$"|T], in_name, [], Acc) ->
  192. split_ne(T, in_qname, [], Acc);
  193. split_ne([$"|T], in_qname, [], Acc) ->
  194. split_ne(T, to_email, lists:reverse(Acc), []);
  195. split_ne([H|T], to_email, Name, Acc) ->
  196. split_ne(T, to_email, Name, [H|Acc]);
  197. split_ne([H|T], State, Name, Acc) ->
  198. split_ne(T, State, Name, [H|Acc]).