@@ -4,19 +4,19 @@ import (
44 "bytes"
55 "context"
66 "crypto/tls"
7- "errors"
87 "fmt"
9- "net/mail"
108 "net/smtp"
9+ "sync/atomic"
1110 "text/template"
12- "time"
1311
12+ "github.com/jordan-wright/email"
1413 "github.com/ovh/cds/sdk"
15- "github.com/ovh/cds/sdk/log"
1614)
1715
1816var smtpUser , smtpPassword , smtpFrom , smtpHost , smtpPort string
1917var smtpTLS , smtpEnable bool
18+ var lastError error
19+ var counter uint64
2020
2121const templateSignedup = `Welcome to CDS,
2222
@@ -64,69 +64,13 @@ func Init(user, password, from, host, port string, tls, disable bool) {
6464
6565// Status verification of smtp configuration, returns OK or KO
6666func Status (ctx context.Context ) sdk.MonitoringStatusLine {
67- if _ , err := smtpClient (ctx ); err != nil {
68- return sdk.MonitoringStatusLine {Component : "SMTP Ping" , Value : "KO: " + err .Error (), Status : sdk .MonitoringStatusAlert }
69- }
70- return sdk.MonitoringStatusLine {Component : "SMTP Ping" , Value : "Connect OK" , Status : sdk .MonitoringStatusOK }
71- }
72-
73- func smtpClient (ctx context.Context ) (* smtp.Client , error ) {
74- if smtpHost == "" || smtpPort == "" || ! smtpEnable {
75- return nil , errors .New ("No SMTP configuration" )
76- }
77-
78- // Connect to the SMTP Server
79- servername := fmt .Sprintf ("%s:%s" , smtpHost , smtpPort )
80-
81- // TLS config
82- tlsconfig := & tls.Config {
83- InsecureSkipVerify : false ,
84- ServerName : smtpHost ,
85- }
86-
87- var c * smtp.Client
88- var err error
89- if smtpTLS {
90- // Here is the key, you need to call tls.Dial instead of smtp.Dial
91- // for smtp servers running on 465 that require an ssl connection
92- // from the very beginning (no starttls)
93- conn , err := tls .Dial ("tcp" , servername , tlsconfig )
94- if err != nil {
95- log .Warning (ctx , "Error with c.Dial:%s\n " , err .Error ())
96- return nil , sdk .WithStack (err )
97- }
98-
99- c , err = smtp .NewClient (conn , smtpHost )
100- if err != nil {
101- log .Warning (ctx , "Error with c.NewClient:%s\n " , err .Error ())
102- return nil , sdk .WithStack (err )
103- }
104- // TLS config
105- tlsconfig := & tls.Config {
106- InsecureSkipVerify : false ,
107- ServerName : smtpHost ,
108- }
109- if err := c .StartTLS (tlsconfig ); err != nil {
110- return nil , sdk .WithStack (err )
111- }
112- } else {
113- c , err = smtp .Dial (servername )
114- if err != nil {
115- log .Warning (ctx , "Error with c.NewClient:%s\n " , err .Error ())
116- return nil , sdk .WithStack (err )
117- }
67+ if ! smtpEnable {
68+ return sdk.MonitoringStatusLine {Component : "SMTP Ping" , Value : "Conf: SMTP Disabled" , Status : sdk .MonitoringStatusWarn }
11869 }
119-
120- // Auth
121- if smtpUser != "" && smtpPassword != "" {
122- auth := smtp .PlainAuth ("" , smtpUser , smtpPassword , smtpHost )
123- if err = c .Auth (auth ); err != nil {
124- log .Warning (ctx , "Error with c.Auth:%s\n " , err .Error ())
125- c .Close ()
126- return nil , err
127- }
70+ if lastError != nil {
71+ return sdk.MonitoringStatusLine {Component : "SMTP Ping" , Value : "KO: " + lastError .Error (), Status : sdk .MonitoringStatusAlert }
12872 }
129- return c , nil
73+ return sdk. MonitoringStatusLine { Component : "SMTP Ping" , Value : fmt . Sprintf ( "OK (%d sent)" , counter ), Status : sdk . MonitoringStatusOK }
13074}
13175
13276// SendMailVerifyToken send mail to verify user account.
@@ -172,83 +116,42 @@ func createTemplate(templ, callbackURL, callbackAPIURL, username, token string)
172116
173117//SendEmail is the core function to send an email
174118func SendEmail (ctx context.Context , subject string , mailContent * bytes.Buffer , userMail string , isHTML bool ) error {
175- from := mail.Address {
176- Name : "" ,
177- Address : smtpFrom ,
178- }
179- to := mail.Address {
180- Name : "" ,
181- Address : userMail ,
182- }
183-
184- // Setup headers
185- headers := make (map [string ]string )
186- headers ["From" ] = smtpFrom
187- headers ["To" ] = to .String ()
188- if sdk .StringIsAscii (subject ) {
189- headers ["Subject" ] = subject
190- } else {
191- // https://tools.ietf.org/html/rfc2047
192- headers ["Subject" ] = "=?UTF-8?Q?" + subject + "?="
193- }
194-
195- // https://tools.ietf.org/html/rfc4021
196- headers ["Date" ] = time .Now ().Format (time .RFC1123Z )
197-
198- // https://tools.ietf.org/html/rfc2392
199- headers ["Message-ID" ] = fmt .Sprintf ("<%d.%s>" , time .Now ().UnixNano (), smtpFrom )
200-
119+ e := email .NewEmail ()
120+ e .From = smtpFrom
121+ e .To = []string {userMail }
122+ e .Subject = subject
123+ e .Text = mailContent .Bytes ()
201124 if isHTML {
202- headers ["Content-Type" ] = `text/html; charset="utf-8"`
203- }
204-
205- // Setup message
206- message := ""
207- for k , v := range headers {
208- message += fmt .Sprintf ("%s: %s\r \n " , k , v )
125+ e .HTML = mailContent .Bytes ()
209126 }
210- message += "\r \n " + mailContent .String ()
211127
212128 if ! smtpEnable {
213129 fmt .Println ("##### NO SMTP DISPLAY MAIL IN CONSOLE ######" )
214130 fmt .Printf ("Subject:%s\n " , subject )
215- fmt .Printf ("Text:%s\n " , message )
131+ fmt .Printf ("Text:%s\n " , string ( e . Text ) )
216132 fmt .Println ("##### END MAIL ######" )
217133 return nil
218134 }
219-
220- c , err := smtpClient (ctx )
221- if err != nil {
222- return sdk .WrapError (err , "Cannot get smtp client" )
223- }
224- defer c .Close ()
225-
226- // To && From
227- if err = c .Mail (from .Address ); err != nil {
228- return sdk .WrapError (err , "Error with c.Mail" )
229- }
230-
231- if err = c .Rcpt (to .Address ); err != nil {
232- return sdk .WrapError (err , "Error with c.Rcpt" )
233- }
234-
235- // Data
236- w , err := c .Data ()
237- if err != nil {
238- return sdk .WrapError (err , "Error with c.Data" )
135+ servername := fmt .Sprintf ("%s:%s" , smtpHost , smtpPort )
136+ var auth smtp.Auth
137+ if smtpUser != "" && smtpPassword != "" {
138+ auth = smtp .PlainAuth ("" , smtpUser , smtpPassword , smtpHost )
239139 }
240-
241- _ , err = w .Write ([]byte (message ))
242- if err != nil {
243- return sdk .WrapError (err , "Error with c.Write" )
140+ var err error
141+ if smtpTLS {
142+ tlsconfig := & tls.Config {
143+ InsecureSkipVerify : false ,
144+ ServerName : smtpHost ,
145+ }
146+ err = e .SendWithStartTLS (servername , auth , tlsconfig )
147+ } else {
148+ err = e .Send (servername , auth )
244149 }
245-
246- err = w .Close ()
247150 if err != nil {
248- return sdk .WrapError (err , "Error with c.Close" )
151+ lastError = err
152+ } else {
153+ atomic .AddUint64 (& counter , 1 )
154+ lastError = nil
249155 }
250-
251- c .Quit ()
252-
253- return nil
156+ return err
254157}
0 commit comments