github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/framework/logs/log_email.go (about)

     1  // the package is exported from github.com/beego/beego/v2/core/logs
     2  
     3  // Copyright 2023. All Rights Reserved.
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //      http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  package logs
    18  
    19  import (
    20  	"crypto/tls"
    21  	"encoding/json"
    22  	"fmt"
    23  	"net"
    24  	"net/smtp"
    25  	"strings"
    26  
    27  	"github.com/pkg/errors"
    28  )
    29  
    30  // SMTPWriter implements LoggerInterface and is used to send emails via given SMTP-server.
    31  type SMTPWriter struct {
    32  	Username           string   `json:"username"`
    33  	Password           string   `json:"password"`
    34  	Host               string   `json:"host"`
    35  	Subject            string   `json:"subject"`
    36  	FromAddress        string   `json:"fromAddress"`
    37  	RecipientAddresses []string `json:"sendTos"`
    38  	Level              int      `json:"level"`
    39  	formatter          LogFormatter
    40  	Formatter          string `json:"formatter"`
    41  }
    42  
    43  // NewSMTPWriter creates the smtp writer.
    44  func newSMTPWriter() Logger {
    45  	res := &SMTPWriter{Level: LevelTrace}
    46  	res.formatter = res
    47  	return res
    48  }
    49  
    50  // Init smtp writer with json config.
    51  // config like:
    52  //
    53  //	{
    54  //		"username":"example@gmail.com",
    55  //		"password:"password",
    56  //		"host":"smtp.gmail.com:465",
    57  //		"subject":"email title",
    58  //		"fromAddress":"from@example.com",
    59  //		"sendTos":["email1","email2"],
    60  //		"level":LevelError
    61  //	}
    62  func (s *SMTPWriter) Init(config string) error {
    63  	res := json.Unmarshal([]byte(config), s)
    64  	if res == nil && len(s.Formatter) > 0 {
    65  		fmtr, ok := GetFormatter(s.Formatter)
    66  		if !ok {
    67  			return errors.New(fmt.Sprintf("the formatter with name: %s not found", s.Formatter))
    68  		}
    69  		s.formatter = fmtr
    70  	}
    71  	return res
    72  }
    73  
    74  func (s *SMTPWriter) getSMTPAuth(host string) smtp.Auth {
    75  	if len(strings.Trim(s.Username, " ")) == 0 && len(strings.Trim(s.Password, " ")) == 0 {
    76  		return nil
    77  	}
    78  	return smtp.PlainAuth(
    79  		"",
    80  		s.Username,
    81  		s.Password,
    82  		host,
    83  	)
    84  }
    85  
    86  func (s *SMTPWriter) SetFormatter(f LogFormatter) {
    87  	s.formatter = f
    88  }
    89  
    90  func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAddress string, recipients []string, msgContent []byte) error {
    91  	client, err := smtp.Dial(hostAddressWithPort)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	host, _, _ := net.SplitHostPort(hostAddressWithPort)
    97  	tlsConn := &tls.Config{
    98  		InsecureSkipVerify: true,
    99  		ServerName:         host,
   100  	}
   101  	if err = client.StartTLS(tlsConn); err != nil {
   102  		return err
   103  	}
   104  
   105  	if auth != nil {
   106  		if err = client.Auth(auth); err != nil {
   107  			return err
   108  		}
   109  	}
   110  
   111  	if err = client.Mail(fromAddress); err != nil {
   112  		return err
   113  	}
   114  
   115  	for _, rec := range recipients {
   116  		if err = client.Rcpt(rec); err != nil {
   117  			return err
   118  		}
   119  	}
   120  
   121  	w, err := client.Data()
   122  	if err != nil {
   123  		return err
   124  	}
   125  	_, err = w.Write(msgContent)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	err = w.Close()
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	return client.Quit()
   136  }
   137  
   138  func (s *SMTPWriter) Format(lm *LogMsg) string {
   139  	return lm.OldStyleFormat()
   140  }
   141  
   142  // WriteMsg writes message in smtp writer.
   143  // Sends an email with subject and only this message.
   144  func (s *SMTPWriter) WriteMsg(lm *LogMsg) error {
   145  	if lm.Level > s.Level && lm.Level != LeverPerformance {
   146  		return nil
   147  	}
   148  
   149  	hp := strings.Split(s.Host, ":")
   150  
   151  	// Set up authentication information.
   152  	auth := s.getSMTPAuth(hp[0])
   153  
   154  	msg := s.Format(lm)
   155  
   156  	// Connect to the server, authenticate, set the sender and recipient,
   157  	// and send the email all in one step.
   158  	contentType := "Content-Type: text/plain" + "; charset=UTF-8"
   159  	mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress +
   160  		">\r\nSubject: " + s.Subject + "\r\n" + contentType + "\r\n\r\n" + fmt.Sprintf(".%s", lm.When.Format("2006-01-02 15:04:05")) + msg)
   161  
   162  	return s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg)
   163  }
   164  
   165  // Flush implementing method. empty.
   166  func (s *SMTPWriter) Flush() {
   167  }
   168  
   169  // Destroy implementing method. empty.
   170  func (s *SMTPWriter) Destroy() {
   171  }
   172  
   173  func init() {
   174  	Register(AdapterMail, newSMTPWriter)
   175  }