4848 " XOAUTH2"
4949]).
5050
51+ -define (TRACE (Options , Format , Args )
52+ ,trace (Options , [$~ , $p , $: , $\s | Format ], [? LINE | Args ])
53+ ).
54+
5155-define (TIMEOUT , 1200000 ).
5256
5357-ifdef (TEST ).
@@ -232,7 +236,7 @@ open(Options) ->
232236 _ ->
233237 smtp_util :mxlookup (RelayDomain )
234238 end ,
235- trace (Options , " MX records for ~s are ~p~n " , [RelayDomain , MXRecords ]),
239+ ? TRACE (Options , " MX records for ~s are ~p~n " , [RelayDomain , MXRecords ]),
236240 Hosts =
237241 case MXRecords of
238242 [] ->
@@ -299,8 +303,8 @@ send_it(Email, Options) ->
299303 Domain ->
300304 [{Domain , smtp_util :mxlookup (Domain )}]
301305 end ,
302- [trace (Options , " MX records for ~s are ~p~n " , [RelayDomain , MXRecords ])
303- || {RelayDomain , MXRecords } <- Relay
306+ [? TRACE (Options , " MX records for ~s are ~p~n " , [RelayDomain , MXRecords ])
307+ || {RelayDomain , MXRecords } <- Relay
304308 ],
305309 Hosts = lists :flatmap (fun ({_ , MXRecords }) -> MXRecords end , Relay ),
306310 case try_smtp_sessions (Hosts , Options , []) of
@@ -375,31 +379,31 @@ fetch_next_host(Retries, RetryCount, [{_Distance, Host} | Tail], RetryList, Opti
375379 is_integer (RetryCount ), RetryCount >= Retries
376380->
377381 % out of chances
378- trace (Options , " retries for ~s exceeded (~p of ~p )~n " , [Host , RetryCount , Retries ]),
382+ ? TRACE (Options , " retries for ~s exceeded (~p of ~p )~n " , [Host , RetryCount , Retries ]),
379383 {Tail , lists :keydelete (Host , 1 , RetryList )};
380384fetch_next_host (Retries , RetryCount , [{Distance , Host } | Tail ], RetryList , Options ) when
381385 is_integer (RetryCount )
382386->
383- trace (Options , " scheduling ~s for retry (~p of ~p )~n " , [Host , RetryCount , Retries ]),
387+ ? TRACE (Options , " scheduling ~s for retry (~p of ~p )~n " , [Host , RetryCount , Retries ]),
384388 {Tail ++ [{Distance , Host }], lists :keydelete (Host , 1 , RetryList ) ++ [{Host , RetryCount + 1 }]};
385389fetch_next_host (0 , _RetryCount , [{_Distance , Host } | Tail ], RetryList , _Options ) ->
386390 % done retrying completely
387391 {Tail , lists :keydelete (Host , 1 , RetryList )};
388392fetch_next_host (Retries , _RetryCount , [{Distance , Host } | Tail ], RetryList , Options ) ->
389393 % otherwise...
390- trace (Options , " scheduling ~s for retry (~p of ~p )~n " , [Host , 1 , Retries ]),
394+ ? TRACE (Options , " scheduling ~s for retry (~p of ~p )~n " , [Host , 1 , Retries ]),
391395 {Tail ++ [{Distance , Host }], lists :keydelete (Host , 1 , RetryList ) ++ [{Host , 1 }]}.
392396
393397- spec open_smtp_session (Host :: string (), Options :: options ()) -> smtp_client_socket ().
394398open_smtp_session (Host , Options ) ->
395399 {ok , Socket , _Host2 , Banner } = connect (Host , Options ),
396- trace (Options , " connected to ~s ; banner was ~s~n " , [Host , Banner ]),
400+ ? TRACE (Options , " connected to ~s ; banner was ~s~n " , [Host , Banner ]),
397401 {ok , Extensions } = try_EHLO (Socket , Options ),
398- trace (Options , " Extensions are ~p~n " , [Extensions ]),
402+ ? TRACE (Options , " Extensions are ~p~n " , [Extensions ]),
399403 {Socket2 , Extensions2 } = try_STARTTLS (Socket , Options , Extensions ),
400- trace (Options , " Extensions are ~p~n " , [Extensions2 ]),
404+ ? TRACE (Options , " Extensions are ~p~n " , [Extensions2 ]),
401405 Authed = try_AUTH (Socket2 , Options , proplists :get_value (<<" AUTH" >>, Extensions2 )),
402- trace (Options , " Authentication status is ~p~n " , [Authed ]),
406+ ? TRACE (Options , " Authentication status is ~p~n " , [Authed ]),
403407 # smtp_client_socket {
404408 socket = Socket2 ,
405409 host = Host ,
@@ -443,11 +447,11 @@ try_MAIL_FROM("<" ++ _ = From, Socket, _Extensions, Options) ->
443447 quit (Socket ),
444448 throw ({temporary_failure , Msg });
445449 {ok , <<" 5" , _Rest /binary >> = Msg } when OnTxError =:= reset ->
446- trace (Options , " Mail FROM rejected: ~p~n " , [Msg ]),
450+ ? TRACE (Options , " Mail FROM rejected: ~p~n " , [Msg ]),
447451 ok = rset_or_quit (Socket ),
448452 throw ({permanent_failure , Msg });
449453 {ok , Msg } ->
450- trace (Options , " Mail FROM rejected: ~p~n " , [Msg ]),
454+ ? TRACE (Options , " Mail FROM rejected: ~p~n " , [Msg ]),
451455 quit (Socket ),
452456 throw ({permanent_failure , Msg })
453457 end ;
@@ -611,7 +615,7 @@ try_AUTH(Socket, Options, AuthTypes) ->
611615 true ->
612616 Username = to_binary (proplists :get_value (username , Options )),
613617 Password = to_binary (proplists :get_value (password , Options )),
614- trace (Options , " Auth types: ~p~n " , [AuthTypes ]),
618+ ? TRACE (Options , " Auth types: ~p~n " , [AuthTypes ]),
615619 Types = re :split (AuthTypes , " " , [{return , list }, trim ]),
616620 case do_AUTH (Socket , Username , Password , Types , Options ) of
617621 false ->
@@ -642,9 +646,9 @@ to_binary(String) when is_list(String) -> list_to_binary(String).
642646) -> boolean ().
643647do_AUTH (Socket , Username , Password , Types , Options ) ->
644648 FixedTypes = [string :to_upper (X ) || X <- Types ],
645- trace (Options , " Fixed types: ~p~n " , [FixedTypes ]),
649+ ? TRACE (Options , " Fixed types: ~p~n " , [FixedTypes ]),
646650 AllowedTypes = [X || X <- ? AUTH_PREFERENCE , lists :member (X , FixedTypes )],
647- trace (Options , " available authentication types, in order of preference: ~p~n " , [AllowedTypes ]),
651+ ? TRACE (Options , " available authentication types, in order of preference: ~p~n " , [AllowedTypes ]),
648652 do_AUTH_each (Socket , Username , Password , AllowedTypes , Options ).
649653
650654- spec do_AUTH_each (
@@ -667,14 +671,14 @@ do_AUTH_each(Socket, Username, Password, ["CRAM-MD5" | Tail], Options) ->
667671 smtp_socket :send (Socket , [String , " \r\n " ]),
668672 case read_possible_multiline_reply (Socket ) of
669673 {ok , <<" 235" , _Rest /binary >>} ->
670- trace (Options , " authentication accepted~n " , []),
674+ ? TRACE (Options , " authentication accepted~n " , []),
671675 true ;
672676 {ok , Msg } ->
673- trace (Options , " authentication rejected: ~s~n " , [Msg ]),
677+ ? TRACE (Options , " authentication rejected: ~s~n " , [Msg ]),
674678 do_AUTH_each (Socket , Username , Password , Tail , Options )
675679 end ;
676680 {ok , Something } ->
677- trace (Options , " got ~s~n " , [Something ]),
681+ ? TRACE (Options , " got ~s~n " , [Something ]),
678682 do_AUTH_each (Socket , Username , Password , Tail , Options )
679683 end ;
680684do_AUTH_each (Socket , Username , Password , [" XOAUTH2" | Tail ], Options ) ->
@@ -692,46 +696,46 @@ do_AUTH_each(Socket, Username, Password, ["LOGIN" | Tail], Options) ->
692696 case is_auth_username_prompt (Prompt ) of
693697 true ->
694698 % % base64 Username: or username:
695- trace (Options , " username prompt~n " , []),
699+ ? TRACE (Options , " username prompt~n " , []),
696700 U = base64 :encode (Username ),
697701 smtp_socket :send (Socket , [U , " \r\n " ]),
698702 {ok , Prompt2 } = read_possible_multiline_reply (Socket ),
699703 case is_auth_password_prompt (Prompt2 ) of
700704 true ->
701705 % % base64 Password: or password:
702- trace (Options , " password prompt~n " , []),
706+ ? TRACE (Options , " password prompt~n " , []),
703707 P = base64 :encode (Password ),
704708 smtp_socket :send (Socket , [P , " \r\n " ]),
705709 case read_possible_multiline_reply (Socket ) of
706710 {ok , <<" 235 " , _Rest /binary >>} ->
707- trace (Options , " authentication accepted~n " , []),
711+ ? TRACE (Options , " authentication accepted~n " , []),
708712 true ;
709713 {ok , Msg } ->
710- trace (Options , " password rejected: ~s " , [Msg ]),
714+ ? TRACE (Options , " password rejected: ~s " , [Msg ]),
711715 do_AUTH_each (Socket , Username , Password , Tail , Options )
712716 end ;
713717 false ->
714- trace (Options , " username rejected: ~s " , [Prompt2 ]),
718+ ? TRACE (Options , " username rejected: ~s " , [Prompt2 ]),
715719 do_AUTH_each (Socket , Username , Password , Tail , Options )
716720 end ;
717721 false ->
718- trace (Options , " got ~s~n " , [Prompt ]),
722+ ? TRACE (Options , " got ~s~n " , [Prompt ]),
719723 do_AUTH_each (Socket , Username , Password , Tail , Options )
720724 end ;
721725do_AUTH_each (Socket , Username , Password , [" PLAIN" | Tail ], Options ) ->
722726 AuthString = base64 :encode (<<0 , Username /binary , 0 , Password /binary >>),
723727 smtp_socket :send (Socket , [" AUTH PLAIN " , AuthString , " \r\n " ]),
724728 case read_possible_multiline_reply (Socket ) of
725729 {ok , <<" 235" , _Rest /binary >>} ->
726- trace (Options , " authentication accepted~n " , []),
730+ ? TRACE (Options , " authentication accepted~n " , []),
727731 true ;
728732 Else ->
729733 % TODO do we need to bother trying the multi-step PLAIN?
730- trace (Options , " authentication rejected ~p~n " , [Else ]),
734+ ? TRACE (Options , " authentication rejected ~p~n " , [Else ]),
731735 do_AUTH_each (Socket , Username , Password , Tail , Options )
732736 end ;
733737do_AUTH_each (Socket , Username , Password , [Type | Tail ], Options ) ->
734- trace (Options , " unsupported AUTH type ~s~n " , [Type ]),
738+ ? TRACE (Options , " unsupported AUTH type ~s~n " , [Type ]),
735739 do_AUTH_each (Socket , Username , Password , Tail , Options ).
736740
737741is_auth_username_prompt (<<" 334 VXNlcm5hbWU6\r\n " >>) -> true ;
@@ -790,24 +794,24 @@ try_HELO(Socket, Options) ->
790794try_STARTTLS (Socket , Options , Extensions ) ->
791795 case {proplists :get_value (tls , Options ), proplists :get_value (<<" STARTTLS" >>, Extensions )} of
792796 {Atom , true } when Atom =:= always ; Atom =:= if_available ->
793- trace (Options , " Starting TLS~n " , []),
797+ ? TRACE (Options , " Starting TLS~n " , []),
794798 case {do_STARTTLS (Socket , Options ), Atom } of
795799 {false , always } ->
796- trace (Options , " TLS failed~n " , []),
800+ ? TRACE (Options , " TLS failed~n " , []),
797801 quit (Socket ),
798802 erlang :throw ({temporary_failure , tls_failed });
799803 {false , if_available } ->
800- trace (Options , " TLS failed~n " , []),
804+ ? TRACE (Options , " TLS failed~n " , []),
801805 {Socket , Extensions };
802806 {{S , E }, _ } ->
803- trace (Options , " TLS started~n " , []),
807+ ? TRACE (Options , " TLS started~n " , []),
804808 {S , E }
805809 end ;
806810 {always , _ } ->
807811 quit (Socket ),
808812 erlang :throw ({missing_requirement , tls });
809813 _ ->
810- trace (Options , " TLS not requested ~p~n " , [Options ]),
814+ ? TRACE (Options , " TLS not requested ~p~n " , [Options ]),
811815 {Socket , Extensions }
812816 end .
813817
@@ -839,8 +843,11 @@ do_STARTTLS(Socket, Options) ->
839843 quit (Socket ),
840844 error_logger :error_msg (" SSL not started.~n " ),
841845 erlang :throw ({permanent_failure , ssl_not_started });
846+ {error , already_ssl } ->
847+ {ok , Extensions } = try_EHLO (Socket , Options ),
848+ {Socket , Extensions };
842849 Else ->
843- trace (Options , " ~p~n " , [Else ]),
850+ ? TRACE (Options , " ~p~n " , [Else ]),
844851 false
845852 end ;
846853 {ok , <<" 4" , _Rest /binary >> = Msg } ->
@@ -999,7 +1006,7 @@ parse_extensions(Reply, Options) ->
9991006 0 ->
10001007 {binstr :to_upper (Body ), true };
10011008 _ ->
1002- trace (Options , " discarding option ~p~n " , [Body ]),
1009+ ? TRACE (Options , " discarding option ~p~n " , [Body ]),
10031010 []
10041011 end
10051012 end
0 commit comments