code.gitea.io/gitea@v1.19.3/modules/log/smtp.go (about)

     1  // Copyright 2014 The Gogs Authors. All rights reserved.
     2  // Copyright 2019 The Gitea Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package log
     6  
     7  import (
     8  	"fmt"
     9  	"net/smtp"
    10  	"strings"
    11  
    12  	"code.gitea.io/gitea/modules/json"
    13  )
    14  
    15  type smtpWriter struct {
    16  	owner *SMTPLogger
    17  }
    18  
    19  // Write sends the message as an email
    20  func (s *smtpWriter) Write(p []byte) (int, error) {
    21  	return s.owner.sendMail(p)
    22  }
    23  
    24  // Close does nothing
    25  func (s *smtpWriter) Close() error {
    26  	return nil
    27  }
    28  
    29  // SMTPLogger implements LoggerProvider and is used to send emails via given SMTP-server.
    30  type SMTPLogger struct {
    31  	WriterLogger
    32  	Username           string   `json:"Username"`
    33  	Password           string   `json:"password"`
    34  	Host               string   `json:"host"`
    35  	Subject            string   `json:"subject"`
    36  	RecipientAddresses []string `json:"sendTos"`
    37  	sendMailFn         func(string, smtp.Auth, string, []string, []byte) error
    38  }
    39  
    40  // NewSMTPLogger creates smtp writer.
    41  func NewSMTPLogger() LoggerProvider {
    42  	s := &SMTPLogger{}
    43  	s.Level = TRACE
    44  	s.sendMailFn = smtp.SendMail
    45  	return s
    46  }
    47  
    48  // Init smtp writer with json config.
    49  // config like:
    50  //
    51  //	{
    52  //		"Username":"example@gmail.com",
    53  //		"password:"password",
    54  //		"host":"smtp.gmail.com:465",
    55  //		"subject":"email title",
    56  //		"sendTos":["email1","email2"],
    57  //		"level":LevelError
    58  //	}
    59  func (log *SMTPLogger) Init(jsonconfig string) error {
    60  	err := json.Unmarshal([]byte(jsonconfig), log)
    61  	if err != nil {
    62  		return fmt.Errorf("Unable to parse JSON: %w", err)
    63  	}
    64  	log.NewWriterLogger(&smtpWriter{
    65  		owner: log,
    66  	})
    67  	log.sendMailFn = smtp.SendMail
    68  	return nil
    69  }
    70  
    71  // WriteMsg writes message in smtp writer.
    72  // it will send an email with subject and only this message.
    73  func (log *SMTPLogger) sendMail(p []byte) (int, error) {
    74  	hp := strings.Split(log.Host, ":")
    75  
    76  	// Set up authentication information.
    77  	auth := smtp.PlainAuth(
    78  		"",
    79  		log.Username,
    80  		log.Password,
    81  		hp[0],
    82  	)
    83  	// Connect to the server, authenticate, set the sender and recipient,
    84  	// and send the email all in one step.
    85  	contentType := "Content-Type: text/plain" + "; charset=UTF-8"
    86  	mailmsg := []byte("To: " + strings.Join(log.RecipientAddresses, ";") + "\r\nFrom: " + log.Username + "<" + log.Username +
    87  		">\r\nSubject: " + log.Subject + "\r\n" + contentType + "\r\n\r\n")
    88  	mailmsg = append(mailmsg, p...)
    89  	return len(p), log.sendMailFn(
    90  		log.Host,
    91  		auth,
    92  		log.Username,
    93  		log.RecipientAddresses,
    94  		mailmsg,
    95  	)
    96  }
    97  
    98  // Content returns the content accumulated in the content provider
    99  func (log *SMTPLogger) Content() (string, error) {
   100  	return "", fmt.Errorf("not supported")
   101  }
   102  
   103  // Flush when log should be flushed
   104  func (log *SMTPLogger) Flush() {
   105  }
   106  
   107  // ReleaseReopen does nothing
   108  func (log *SMTPLogger) ReleaseReopen() error {
   109  	return nil
   110  }
   111  
   112  // GetName returns the default name for this implementation
   113  func (log *SMTPLogger) GetName() string {
   114  	return "smtp"
   115  }
   116  
   117  func init() {
   118  	Register("smtp", NewSMTPLogger)
   119  }