github.com/cs3org/reva/v2@v2.27.7/pkg/smtpclient/smtpclient.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package smtpclient
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/base64"
    24  	"fmt"
    25  	"net/smtp"
    26  	"os"
    27  	"strings"
    28  	"time"
    29  
    30  	"github.com/google/uuid"
    31  	"github.com/pkg/errors"
    32  )
    33  
    34  // SMTPCredentials stores the credentials required to connect to an SMTP server.
    35  type SMTPCredentials struct {
    36  	SenderLogin    string `mapstructure:"sender_login" docs:";The login to be used by sender."`
    37  	SenderMail     string `mapstructure:"sender_mail" docs:";The email to be used to send mails."`
    38  	SenderPassword string `mapstructure:"sender_password" docs:";The sender's password."`
    39  	SMTPServer     string `mapstructure:"smtp_server" docs:";The hostname of the SMTP server."`
    40  	SMTPPort       int    `mapstructure:"smtp_port" docs:"587;The port on which the SMTP daemon is running."`
    41  	DisableAuth    bool   `mapstructure:"disable_auth" docs:"false;Whether to disable SMTP auth."`
    42  	LocalName      string `mapstructure:"local_name" docs:";The host name to be used for unauthenticated SMTP."`
    43  }
    44  
    45  // NewSMTPCredentials creates a new SMTPCredentials object with the details of the passed object with sane defaults.
    46  func NewSMTPCredentials(c *SMTPCredentials) *SMTPCredentials {
    47  	creds := c
    48  
    49  	if creds.SMTPPort == 0 {
    50  		creds.SMTPPort = 587
    51  	}
    52  	if !creds.DisableAuth && creds.SenderPassword == "" {
    53  		creds.SenderPassword = os.Getenv("REVA_SMTP_SENDER_PASSWORD")
    54  	}
    55  	if creds.LocalName == "" {
    56  		tokens := strings.Split(creds.SenderMail, "@")
    57  		creds.LocalName = tokens[len(tokens)-1]
    58  	}
    59  	if creds.SenderLogin == "" {
    60  		creds.SenderLogin = creds.SenderMail
    61  	}
    62  	return creds
    63  }
    64  
    65  // SendMail allows sending mails using a set of client credentials.
    66  func (creds *SMTPCredentials) SendMail(recipient, subject, body string) error {
    67  
    68  	headers := map[string]string{
    69  		"From":                      creds.SenderMail,
    70  		"To":                        recipient,
    71  		"Subject":                   subject,
    72  		"Date":                      time.Now().Format(time.RFC1123Z),
    73  		"Message-ID":                uuid.New().String(),
    74  		"MIME-Version":              "1.0",
    75  		"Content-Type":              "text/plain; charset=\"utf-8\"",
    76  		"Content-Transfer-Encoding": "base64",
    77  	}
    78  
    79  	message := ""
    80  	for k, v := range headers {
    81  		message += fmt.Sprintf("%s: %s\r\n", k, v)
    82  	}
    83  	message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))
    84  
    85  	if creds.DisableAuth {
    86  		return creds.sendMailSMTP(recipient, subject, message)
    87  	}
    88  	return creds.sendMailAuthSMTP(recipient, subject, message)
    89  }
    90  
    91  func (creds *SMTPCredentials) sendMailAuthSMTP(recipient, subject, message string) error {
    92  
    93  	auth := smtp.PlainAuth("", creds.SenderLogin, creds.SenderPassword, creds.SMTPServer)
    94  
    95  	err := smtp.SendMail(
    96  		fmt.Sprintf("%s:%d", creds.SMTPServer, creds.SMTPPort),
    97  		auth,
    98  		creds.SenderMail,
    99  		[]string{recipient},
   100  		[]byte(message),
   101  	)
   102  	if err != nil {
   103  		err = errors.Wrap(err, "smtpclient: error sending mail")
   104  		return err
   105  	}
   106  
   107  	return nil
   108  }
   109  
   110  func (creds *SMTPCredentials) sendMailSMTP(recipient, subject, message string) error {
   111  
   112  	c, err := smtp.Dial(fmt.Sprintf("%s:%d", creds.SMTPServer, creds.SMTPPort))
   113  	if err != nil {
   114  		return err
   115  	}
   116  	defer c.Close()
   117  
   118  	if err = c.Hello(creds.LocalName); err != nil {
   119  		return err
   120  	}
   121  	if err = c.Mail(creds.SenderMail); err != nil {
   122  		return err
   123  	}
   124  	if err = c.Rcpt(recipient); err != nil {
   125  		return err
   126  	}
   127  
   128  	wc, err := c.Data()
   129  	if err != nil {
   130  		return err
   131  	}
   132  	defer wc.Close()
   133  
   134  	buf := bytes.NewBufferString(message)
   135  	if _, err = buf.WriteTo(wc); err != nil {
   136  		return err
   137  	}
   138  
   139  	return nil
   140  }