github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/state/impl_send_mail_storage.go (about)

     1  /*
     2   * Copyright (c) 2022-present unTill Pro, Ltd.
     3   */
     4  
     5  package state
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/voedger/voedger/pkg/appdef"
    11  	"github.com/voedger/voedger/pkg/goutils/logger"
    12  	"github.com/voedger/voedger/pkg/istructs"
    13  	"github.com/voedger/voedger/pkg/state/smtptest"
    14  	coreutils "github.com/voedger/voedger/pkg/utils"
    15  	"github.com/wneessen/go-mail"
    16  )
    17  
    18  type sendMailStorage struct {
    19  	messages chan smtptest.Message // not nil in tests only
    20  }
    21  
    22  type sendMailValueBuilder struct {
    23  	istructs.IStateValueBuilder
    24  }
    25  
    26  func (s *sendMailStorage) NewKeyBuilder(appdef.QName, istructs.IStateKeyBuilder) istructs.IStateKeyBuilder {
    27  	return &sendMailKeyBuilder{
    28  		keyBuilder: newKeyBuilder(SendMail, appdef.NullQName),
    29  		to:         make([]string, 0),
    30  		cc:         make([]string, 0),
    31  		bcc:        make([]string, 0),
    32  	}
    33  }
    34  func (s *sendMailStorage) Validate(items []ApplyBatchItem) (err error) {
    35  	for _, item := range items {
    36  		k := item.key.(*sendMailKeyBuilder)
    37  
    38  		mustExist := func(field string) (err error) {
    39  			_, ok := k.data[field]
    40  			if !ok {
    41  				return fmt.Errorf("'%s': %w", field, ErrNotFound)
    42  			}
    43  			return
    44  		}
    45  
    46  		err = mustExist(Field_Host)
    47  		if err != nil {
    48  			return
    49  		}
    50  		err = mustExist(Field_Port)
    51  		if err != nil {
    52  			return
    53  		}
    54  		err = mustExist(Field_Username)
    55  		if err != nil {
    56  			return
    57  		}
    58  		err = mustExist(Field_Password)
    59  		if err != nil {
    60  			return
    61  		}
    62  		err = mustExist(Field_From)
    63  		if err != nil {
    64  			return
    65  		}
    66  		if len(item.key.(*sendMailKeyBuilder).to) == 0 {
    67  			return fmt.Errorf("'%s': %w", Field_To, ErrNotFound)
    68  		}
    69  	}
    70  	return nil
    71  }
    72  func (s *sendMailStorage) ApplyBatch(items []ApplyBatchItem) (err error) {
    73  	stringOrEmpty := func(k *sendMailKeyBuilder, name string) string {
    74  		if intf, ok := k.data[name]; ok {
    75  			return intf.(string)
    76  		}
    77  		return ""
    78  	}
    79  	for _, item := range items {
    80  		k := item.key.(*sendMailKeyBuilder)
    81  
    82  		msg := mail.NewMsg()
    83  		msg.Subject(stringOrEmpty(k, Field_Subject))
    84  		err = msg.From(k.data[Field_From].(string))
    85  		if err != nil {
    86  			return
    87  		}
    88  		err = msg.To(k.to...)
    89  		if err != nil {
    90  			return
    91  		}
    92  		err = msg.Cc(k.cc...)
    93  		if err != nil {
    94  			return
    95  		}
    96  		err = msg.Bcc(k.bcc...)
    97  		if err != nil {
    98  			return
    99  		}
   100  		msg.SetBodyString(mail.TypeTextHTML, stringOrEmpty(k, Field_Body))
   101  		msg.SetCharset(mail.CharsetUTF8)
   102  
   103  		opts := []mail.Option{
   104  			mail.WithPort(int(k.data[Field_Port].(int32))),
   105  			mail.WithUsername(k.data[Field_Username].(string)),
   106  			mail.WithPassword(k.data[Field_Password].(string)),
   107  			mail.WithSMTPAuth(mail.SMTPAuthPlain),
   108  		}
   109  
   110  		if coreutils.IsTest() {
   111  			opts = append(opts, mail.WithTLSPolicy(mail.NoTLS))
   112  		}
   113  
   114  		logger.Info(fmt.Sprintf("send mail '%s' from '%s' to %s, cc %s, bcc %s", stringOrEmpty(k, Field_Subject), k.data[Field_From], k.to, k.cc, k.bcc))
   115  
   116  		if s.messages != nil {
   117  			// happens in tests only
   118  			m := smtptest.Message{
   119  				Subject: stringOrEmpty(k, Field_Subject),
   120  				From:    k.data[Field_From].(string),
   121  				To:      k.to,
   122  				CC:      k.cc,
   123  				BCC:     k.bcc,
   124  				Body:    stringOrEmpty(k, Field_Body),
   125  			}
   126  			s.messages <- m
   127  		} else {
   128  			c, e := mail.NewClient(k.data[Field_Host].(string), opts...)
   129  			if e != nil {
   130  				return e
   131  			}
   132  			err = c.DialAndSend(msg)
   133  			if err != nil {
   134  				return err
   135  			}
   136  		}
   137  
   138  		logger.Info(fmt.Sprintf("mail '%s' from '%s' to %s, cc %s, bcc %s successfully sent", stringOrEmpty(k, Field_Subject), k.data[Field_From], k.to, k.cc, k.bcc))
   139  	}
   140  	return nil
   141  }
   142  func (s *sendMailStorage) ProvideValueBuilder(istructs.IStateKeyBuilder, istructs.IStateValueBuilder) (istructs.IStateValueBuilder, error) {
   143  	return &sendMailValueBuilder{}, nil
   144  }