Skip to content

Commit 04c8bcb

Browse files
Increased tracing and handle when socket is already using TLS
1 parent 013ea71 commit 04c8bcb

1 file changed

Lines changed: 66 additions & 45 deletions

File tree

‎src/gen_smtp_client.erl‎

Lines changed: 66 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -277,46 +277,28 @@ close(#smtp_client_socket{socket = Socket}) ->
277277
quit(Socket).
278278

279279
-spec send_it(Email :: email(), Options :: options()) ->
280-
binary()
281-
| smtp_session_error().
280+
binary()
281+
| smtp_session_error().
282282
send_it(Email, Options) ->
283283
NoMXLookups = proplists:get_value(no_mx_lookups, Options, false),
284-
Relay = case proplists:get_value(relay, Options) of
285-
<<Domain/binary>> when NoMXLookups =:= 'true' ->
286-
%% maybe we're supposed to relay to a host directly
287-
[{to_string(Domain), [{0, to_string(Domain)}]}];
288-
<<Domain/binary>> ->
289-
[{to_string(Domain), smtp_util:mxlookup(to_string(Domain))}];
290-
[<<_/binary>> | _ ] = Domains when NoMXLookups =:= 'true' ->
291-
%% maybe we're supposed to relay to a host directly
292-
[{to_string(Domain), {0, to_string(Domain)}} || Domain <- Domains];
293-
[<<_/binary>> | _ ] = Domains ->
294-
[{to_string(Domain), smtp_util:mxlookup(to_string(Domain))} || Domain <- Domains];
295-
[List | _ ] = Domains when is_list(List) andalso NoMXLookups =:= 'true' ->
296-
%% maybe we're supposed to relay to a host directly
297-
[{Domain, [{0, Domain}]} || Domain <- Domains];
298-
[List | _ ] = Domains when is_list(List) ->
299-
[{Domain, smtp_util:mxlookup(Domain)} || Domain <- Domains];
300-
Domain when NoMXLookups =:= 'true' ->
301-
%% maybe we're supposed to relay to a host directly
302-
[{Domain, [{0, Domain}]}];
303-
Domain ->
304-
[{Domain, smtp_util:mxlookup(Domain)}]
305-
end,
306-
[?TRACE(Options, "MX records for ~s are ~p~n", [RelayDomain, MXRecords])
307-
|| {RelayDomain, MXRecords} <- Relay
284+
Domain = proplists:get_value(relay, Options),
285+
Relay = get_mx_records(Domain, NoMXLookups, Options),
286+
287+
[?TRACE(Options, "MX records for ~s are ~p~n", [RelayDomain, MXRecords])
288+
|| {RelayDomain, MXRecords} <- Relay
308289
],
290+
309291
Hosts = lists:flatmap(fun({_, MXRecords}) -> MXRecords end, Relay),
310292
case try_smtp_sessions(Hosts, Options, []) of
311293
{error, _, _} = Error ->
312294
Error;
313295
{ok, ClientSocket} ->
314296
#smtp_client_socket{
315-
socket = Socket,
316-
host = Host,
317-
extensions = Extensions,
318-
options = Options1
319-
} = ClientSocket,
297+
socket = Socket,
298+
host = Host,
299+
extensions = Extensions,
300+
options = Options1
301+
} = ClientSocket,
320302
try
321303
try_sending_it(Email, Socket, Extensions, Options1)
322304
catch
@@ -327,11 +309,34 @@ send_it(Email, Options) ->
327309
end
328310
end.
329311

312+
get_mx_records(<<Domain/binary>>, 'true', Options) ->
313+
%% maybe we're supposed to relay to a host directly
314+
?TRACE(Options, "relaying directly to host ~s~n", [Domain]),
315+
[{to_string(Domain), [{0, to_string(Domain)}]}];
316+
get_mx_records(<<Domain/binary>>, 'false', Options) ->
317+
?TRACE(Options, "mx lookup on ~s: ~p~n", [Domain, smtp_util:mxlookup(to_string(Domain))]),
318+
[{to_string(Domain), smtp_util:mxlookup(to_string(Domain))}];
319+
get_mx_records([<<_/binary>> | _ ] = Domains, 'true', _Options) ->
320+
%% maybe we're supposed to relay to a host directly
321+
[{to_string(Domain), {0, to_string(Domain)}} || Domain <- Domains];
322+
get_mx_records([<<_/binary>> | _ ] = Domains, 'false', _Options) ->
323+
[{to_string(Domain), smtp_util:mxlookup(to_string(Domain))} || Domain <- Domains];
324+
get_mx_records([List | _ ] = Domains, 'true', _Options) when is_list(List) ->
325+
%% maybe we're supposed to relay to a host directly
326+
[{Domain, [{0, Domain}]} || Domain <- Domains];
327+
get_mx_records([List | _ ] = Domains, 'false', _Options) when is_list(List) ->
328+
[{Domain, smtp_util:mxlookup(Domain)} || Domain <- Domains];
329+
get_mx_records(Domain, 'true', _Options) ->
330+
%% maybe we're supposed to relay to a host directly
331+
[{Domain, [{0, Domain}]}];
332+
get_mx_records(Domain, 'false', _Options) ->
333+
[{Domain, smtp_util:mxlookup(Domain)}].
334+
330335
-spec try_smtp_sessions(
331-
Hosts :: [{non_neg_integer(), string()}, ...], Options :: options(), RetryList :: list()
332-
) ->
333-
{ok, smtp_client_socket()}
334-
| smtp_session_error().
336+
Hosts :: [{non_neg_integer(), string()}, ...], Options :: options(), RetryList :: list()
337+
) ->
338+
{ok, smtp_client_socket()}
339+
| smtp_session_error().
335340
try_smtp_sessions([{_Distance, Host} | _Tail] = Hosts, Options, RetryList) ->
336341
try
337342
{ok, open_smtp_session(Host, Options)}
@@ -671,10 +676,10 @@ do_AUTH_each(Socket, Username, Password, ["CRAM-MD5" | Tail], Options) ->
671676
smtp_socket:send(Socket, [String, "\r\n"]),
672677
case read_possible_multiline_reply(Socket) of
673678
{ok, <<"235", _Rest/binary>>} ->
674-
?TRACE(Options, "authentication accepted~n", []),
679+
?TRACE(Options, "CRAM-MD5 authentication accepted~n", []),
675680
true;
676681
{ok, Msg} ->
677-
?TRACE(Options, "authentication rejected: ~s~n", [Msg]),
682+
?TRACE(Options, "CRAM-mD5 authentication rejected: ~s~n", [Msg]),
678683
do_AUTH_each(Socket, Username, Password, Tail, Options)
679684
end;
680685
{ok, Something} ->
@@ -686,13 +691,17 @@ do_AUTH_each(Socket, Username, Password, ["XOAUTH2" | Tail], Options) ->
686691
smtp_socket:send(Socket, ["AUTH XOAUTH2 ", Str, "\r\n"]),
687692
case read_possible_multiline_reply(Socket) of
688693
{ok, <<"235", _Rest/binary>>} ->
694+
?TRACE(Options, "XOAUTH2 authentication accepted~n", []),
689695
true;
690696
{ok, _Msg} ->
691697
do_AUTH_each(Socket, Username, Password, Tail, Options)
692698
end;
693699
do_AUTH_each(Socket, Username, Password, ["LOGIN" | Tail], Options) ->
700+
?TRACE(Options, "trying AUTH LOGIN: ~p~n", [Socket]),
694701
smtp_socket:send(Socket, "AUTH LOGIN\r\n"),
695-
{ok, Prompt} = read_possible_multiline_reply(Socket),
702+
Return = read_possible_multiline_reply(Socket, Options),
703+
?TRACE(Options, "AUTH LOGIN prompt return: ~p~n", [Return]),
704+
{ok, Prompt} = Return,
696705
case is_auth_username_prompt(Prompt) of
697706
true ->
698707
%% base64 Username: or username:
@@ -719,19 +728,20 @@ do_AUTH_each(Socket, Username, Password, ["LOGIN" | Tail], Options) ->
719728
do_AUTH_each(Socket, Username, Password, Tail, Options)
720729
end;
721730
false ->
722-
?TRACE(Options, "got ~s~n", [Prompt]),
731+
?TRACE(Options, "not an auth login prompt, got ~s~n", [Prompt]),
723732
do_AUTH_each(Socket, Username, Password, Tail, Options)
724733
end;
725734
do_AUTH_each(Socket, Username, Password, ["PLAIN" | Tail], Options) ->
735+
?TRACE(Options, "trying AUTH PLAIN~n", []),
726736
AuthString = base64:encode(<<0, Username/binary, 0, Password/binary>>),
727737
smtp_socket:send(Socket, ["AUTH PLAIN ", AuthString, "\r\n"]),
728738
case read_possible_multiline_reply(Socket) of
729739
{ok, <<"235", _Rest/binary>>} ->
730-
?TRACE(Options, "authentication accepted~n", []),
740+
?TRACE(Options, "PLAIN authentication accepted~n", []),
731741
true;
732742
Else ->
733-
% TODO do we need to bother trying the multi-step PLAIN?
734-
?TRACE(Options, "authentication rejected ~p~n", [Else]),
743+
% TODO do we need to bother trying the multi-step PLAIN?
744+
?TRACE(Options, "PLAIN authentication rejected ~p~n", [Else]),
735745
do_AUTH_each(Socket, Username, Password, Tail, Options)
736746
end;
737747
do_AUTH_each(Socket, Username, Password, [Type | Tail], Options) ->
@@ -803,6 +813,9 @@ try_STARTTLS(Socket, Options, Extensions) ->
803813
{false, if_available} ->
804814
?TRACE(Options, "TLS failed~n", []),
805815
{Socket, Extensions};
816+
{true, _} ->
817+
?TRACE(Options, "TLS already started~n", []),
818+
{Socket, Extensions};
806819
{{S, E}, _} ->
807820
?TRACE(Options, "TLS started~n", []),
808821
{S, E}
@@ -844,8 +857,8 @@ do_STARTTLS(Socket, Options) ->
844857
error_logger:error_msg("SSL not started.~n"),
845858
erlang:throw({permanent_failure, ssl_not_started});
846859
{error, already_ssl} ->
847-
{ok, Extensions} = try_EHLO(Socket, Options),
848-
{Socket, Extensions};
860+
?TRACE(Options, "already SSL", []),
861+
true;
849862
Else ->
850863
?TRACE(Options, "~p~n", [Else]),
851864
false
@@ -889,6 +902,7 @@ connect(Host, Options) ->
889902
undefined -> 5000;
890903
OTimeout -> OTimeout
891904
end,
905+
?TRACE(Options, "connect to ~s://~s:~p~n", [Proto, Host, Port]),
892906
case smtp_socket:connect(Proto, Host, Port, SockOpts, Timeout) of
893907
{ok, Socket} ->
894908
case read_possible_multiline_reply(Socket) of
@@ -908,6 +922,9 @@ connect(Host, Options) ->
908922
%% read a multiline reply (eg. EHLO reply)
909923
-spec read_possible_multiline_reply(Socket :: smtp_socket:socket()) -> {ok, binary()}.
910924
read_possible_multiline_reply(Socket) ->
925+
read_possible_multiline_reply(Socket, 'undefined').
926+
927+
read_possible_multiline_reply(Socket, Options) ->
911928
case smtp_socket:recv(Socket, 0, ?TIMEOUT) of
912929
{ok, Packet} ->
913930
case binstr:substr(Packet, 4, 1) of
@@ -917,12 +934,15 @@ read_possible_multiline_reply(Socket) ->
917934
<<" ">> ->
918935
{ok, Packet}
919936
end;
937+
Error when Options =:= undefined ->
938+
throw({network_failure, Error});
920939
Error ->
940+
?TRACE(Options, "failed to recv packet: ~p~n", [Error]),
921941
throw({network_failure, Error})
922942
end.
923943

924944
-spec read_multiline_reply(Socket :: smtp_socket:socket(), Code :: binary(), Acc :: [binary()]) ->
925-
{ok, binary()}.
945+
{ok, binary()}.
926946
read_multiline_reply(Socket, Code, Acc) ->
927947
case smtp_socket:recv(Socket, 0, ?TIMEOUT) of
928948
{ok, Packet} ->
@@ -936,6 +956,7 @@ read_multiline_reply(Socket, Code, Acc) ->
936956
throw({unexpected_response, lists:reverse([Packet | Acc])})
937957
end;
938958
Error ->
959+
io:format("~p: network failure: ~p~n", [?LINE, Error]),
939960
throw({network_failure, Error})
940961
end.
941962

0 commit comments

Comments
 (0)