This is a creation in Article, where the information may have evolved or changed.
Struggle with the net/smtp of the Go language for a day and record the journey.
First, use the most standard example
Host: = Net. Joinhostport (hostnameport)
username password, hostname)
To: = []string{address}
Address +
"\ r \ n" +
"Subject:" +
Title +
"\ r \ n" +
"\ r \ n" +
Content +
"\ r \ n")
from, to, MSG)
The program continues to report a unencrypted connection error. The original new version of SMTP forces the message to be sent over an SSL connection in order to prevent the password from being transmitted in clear text. But my hands on the server does not have SSL connection, had to go to the library to see where to make the judgment, find auth.go inside the func Start () in such a passage
If!server. TLS {
Advertised: = False
For _, Mechanism: = Range server. Auth {
if mechanism = = "PLAIN" {
Advertised = True
Break
}
}
If!advertised {
Return "", Nil, errors. New ("Unencrypted Connection")
}
}
It seems that the judgment was carried out here. Find a way to spoof TLS links on the web.
First, add in the code
/*use Unssl to link mail server*/
Type Unencryptedauth struct {
Smtp. Auth
}
Func (a Unencryptedauth) Start (server *smtp. ServerInfo) (String, []byte, error) {
S: = *server
S.tls = True
Login, resp, th: = A.auth.start (&s)
Return "LOGIN", resp, th
}
Set the value of TLS to true to write the e-mail section
Auth: = Unencryptedauth {
Smtp. Plainauth (
"",
Username
Password
Hostname
)
}
from, to, MSG)
This link is set up, and the reported error becomes unrecognized authentication type. The return value of Func Start () is checked to
Return "PLAIN", resp, nil
Originally here forced to plain landing. Refer to previous methods to modify ideas, rewrite the Start method
Type Loginauth struct {
Username, password string
}
Func loginauth (username, password string) smtp. Auth {
return &loginauth{username, password}
}
Func (a *loginauth) Start (server *smtp. ServerInfo) (String, []byte, error) {
Return "LOGIN", Nil, nil
}
Func (a *loginauth) Next (fromserver []byte, more bool) ([]byte, error) {
Command: = String (fromserver)
Command = strings. Trimspace (command)
Command = strings. Trimsuffix (Command, ":")
Command = strings. ToLower (command)
If more {
if (Command = = "username") {
return []byte (FMT. Sprintf ("%s", A.username)), nil
} else if (Command = = "Password") {
return []byte (FMT. Sprintf ("%s", A.password)), nil
} else {
We ' ve already sent everything.
return nil, FMT. Errorf ("Unexpected Server Challenge:%s", command)
}
}
return nil, Nil
}
Login authentication Mode protocol and plain different, so the next method also rewrite, or the unexpected server challenge error, so that can successfully use the user name and password authentication, e-mail authentication part of this write:
password)
This will make it possible to send the message successfully.
But when I swapped with another mail server, there was another certificate signed by unknown authority
When you deploy to a server, the error is displayed as cannot validate certificate for 10.11.64.80 because it doesn ' t contain any IP SANS
In short, they are similar to the issue of authentication. The difference between the two servers is that the first one uses 465 ports, namely Smtps, and the second uses 25 ports.
View Smtp.go found in the Func SendMail ()
If OK, _: = C.extension ("STARTTLS"); OK {
Config: = &tls. Config{servername:c.servername}
If Testhookstarttls! = Nil {
Testhookstarttls (config)
}
If err = c.starttls (config); Err! = Nil {
return err
}
}
I simply copy the SendMail method, remove this section of judgment, while the SMTP involved in the Func and struct are copied out, wrote a new. Go, use this new sendmail directly when you send an email. Some of the original public methods and structures do not have to be copied out, directly to the SMTP. Call, so that you can directly use port 25 of the server to send mail.
Although the message was sent successfully, but the total output error in the View log is the mail OK queued as XXXX, looked very uncomfortable, but this output is not like a mistake. Follow the steps of Telnet hostname port against the SendMail execution process. Found after sending the data command, you will receive a reply code 354, receive input message content, with a period return to the end, you will receive a 250 reply. In the code, send data, receive 354, and then send the message content, the code does not receive this 250. Finally send quit, here received is the previous reply code 250, and quit the normal recovery code 221 for comparison, the program will return error. I also do not know which function can only receive replies, simple, simply in the QUIT function sent two times quit, judge the first return 250, the second return 221, finally no error.
After studying this function, I know a lot about SMTP from ignorance to understanding. In addition, to fundamentally solve the problem, or upgrade to SSL it!