@@ -6,9 +6,11 @@ package smtp
6
6
7
7
import (
8
8
"crypto/tls"
9
- "errors"
10
9
"fmt"
10
+ "net"
11
11
"net/smtp"
12
+ "os"
13
+ "strconv"
12
14
13
15
"code.gitea.io/gitea/models"
14
16
)
@@ -42,40 +44,62 @@ func (auth *loginAuthenticator) Next(fromServer []byte, more bool) ([]byte, erro
42
44
43
45
// SMTP authentication type names.
44
46
const (
45
- PlainAuthentication = "PLAIN"
46
- LoginAuthentication = "LOGIN"
47
+ PlainAuthentication = "PLAIN"
48
+ LoginAuthentication = "LOGIN"
49
+ CRAMMD5Authentication = "CRAM-MD5"
47
50
)
48
51
49
52
// Authenticators contains available SMTP authentication type names.
50
- var Authenticators = []string {PlainAuthentication , LoginAuthentication }
53
+ var Authenticators = []string {PlainAuthentication , LoginAuthentication , CRAMMD5Authentication }
51
54
52
55
// Authenticate performs an SMTP authentication.
53
56
func Authenticate (a smtp.Auth , source * Source ) error {
54
- c , err := smtp .Dial (fmt .Sprintf ("%s:%d" , source .Host , source .Port ))
57
+ tlsConfig := & tls.Config {
58
+ InsecureSkipVerify : source .SkipVerify ,
59
+ ServerName : source .Host ,
60
+ }
61
+
62
+ conn , err := net .Dial ("tcp" , net .JoinHostPort (source .Host , strconv .Itoa (source .Port )))
55
63
if err != nil {
56
64
return err
57
65
}
58
- defer c .Close ()
66
+ defer conn .Close ()
59
67
60
- if err = c .Hello ("gogs" ); err != nil {
61
- return err
68
+ if source .UseTLS () {
69
+ conn = tls .Client (conn , tlsConfig )
70
+ }
71
+
72
+ client , err := smtp .NewClient (conn , source .Host )
73
+ if err != nil {
74
+ return fmt .Errorf ("failed to create NewClient: %w" , err )
62
75
}
76
+ defer client .Close ()
63
77
64
- if source .TLS {
65
- if ok , _ := c .Extension ("STARTTLS" ); ok {
66
- if err = c .StartTLS (& tls.Config {
67
- InsecureSkipVerify : source .SkipVerify ,
68
- ServerName : source .Host ,
69
- }); err != nil {
70
- return err
78
+ if ! source .DisableHelo {
79
+ hostname := source .HeloHostname
80
+ if len (hostname ) == 0 {
81
+ hostname , err = os .Hostname ()
82
+ if err != nil {
83
+ return fmt .Errorf ("failed to find Hostname: %w" , err )
71
84
}
72
- } else {
73
- return errors .New ("SMTP server unsupports TLS" )
85
+ }
86
+
87
+ if err = client .Hello (hostname ); err != nil {
88
+ return fmt .Errorf ("failed to send Helo: %w" , err )
89
+ }
90
+ }
91
+
92
+ // If not using SMTPS, always use STARTTLS if available
93
+ hasStartTLS , _ := client .Extension ("STARTTLS" )
94
+ if ! source .UseTLS () && hasStartTLS {
95
+ if err = client .StartTLS (tlsConfig ); err != nil {
96
+ return fmt .Errorf ("failed to start StartTLS: %v" , err )
74
97
}
75
98
}
76
99
77
- if ok , _ := c .Extension ("AUTH" ); ok {
78
- return c .Auth (a )
100
+ if ok , _ := client .Extension ("AUTH" ); ok {
101
+ return client .Auth (a )
79
102
}
103
+
80
104
return models .ErrUnsupportedLoginType
81
105
}
0 commit comments