PageRenderTime 34ms CodeModel.GetById 16ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

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