smtp.SendMail actually does a great job, but the fact that it always uses smtp.Dial make it less flexible both for testing and for certain cases like ours, where we wanted to customize the Client.localName
In fact, in certain operations, Client.localName must correspond to the FQDN hostname sending the email (always localhost in the current implementation), this lack of flexibility led us to duplicate the entire SendMail (and tests) code just to address this issue.
I propose that we add a new public method smtp.SendMailWithDialer or smtp.SendMailWithDialerFunc and a new type Dialer/DialerFunc
type Dialer func() (*Client, error) // or DialerFunc ?
func SendMailWithDialer(dial Dialer, a Auth, from string, to []string, msg []byte) error
The change set required is very minimal and backward compatible, smtp.SendMail could use smtp.SendMailWithDialer just by passing smtp.Dial as the dialer:
func makeDialer(addr string) func() (*Client, error) {
return func() (*Client, error) {
return Dial(addr)
}
}
func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
return SendMailWithDialer(makeDialer(addr), a, from, to, msg)
}
This would allow for much more control both for testing and real uses cases with minimum code, for example:
func myDialer() (*smtp.Client, error) {
cl, err := Dial("remoteSmtp:25")
if err != nil { return nil, err }
if err := cl.Hello("my_FQDN") {
return nil, err
}
return cl, nil
}
smtp.SendMailWithDialer(myDialer, auth, from, to, msg)
I am willing to make a CL if it is accepted
Edit:
-
At first the proposal was about adding SendMailWithClient, but it turned out that line validation would be duplicate both in SendMailWithClient and SendMail as the validation must occur before the dial
-
The proposal included a proposal to make config.localName public, but since Client.Hello exists and SendMail uses Client.hello internally which does nothing if a Hello was called before this change is no longer required as the Dialer function could call Hello before passing to SendMailWithDialer
smtp.SendMailactually does a great job, but the fact that it always usessmtp.Dialmake it less flexible both for testing and for certain cases like ours, where we wanted to customize theClient.localNameIn fact, in certain operations,
Client.localNamemust correspond to the FQDN hostname sending the email (alwayslocalhostin the current implementation), this lack of flexibility led us to duplicate the entire SendMail (and tests) code just to address this issue.I propose that we add a new public method
smtp.SendMailWithDialerorsmtp.SendMailWithDialerFuncand a new typeDialer/DialerFuncThe change set required is very minimal and backward compatible,
smtp.SendMailcould usesmtp.SendMailWithDialerjust by passingsmtp.Dialas the dialer:This would allow for much more control both for testing and real uses cases with minimum code, for example:
I am willing to make a CL if it is accepted
Edit:
At first the proposal was about adding
SendMailWithClient, but it turned out that line validation would be duplicate both inSendMailWithClientandSendMailas the validation must occur before the dialThe proposal included a proposal to make
config.localNamepublic, but sinceClient.Helloexists and SendMail usesClient.hellointernally which does nothing if a Hello was called before this change is no longer required as the Dialer function could callHellobefore passing toSendMailWithDialer