github.com/aldelo/common@v1.5.1/wrapper/ses/ses.go (about)

     1  package ses
     2  
     3  /*
     4   * Copyright 2020-2023 Aldelo, LP
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  // =================================================================================================================
    20  // AWS CREDENTIAL:
    21  //		use $> aws configure (to set aws access key and secret to target machine)
    22  //		Store AWS Access ID and Secret Key into Default Profile Using '$ aws configure' cli
    23  //
    24  // To Install & Setup AWS CLI on Host:
    25  //		1) https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html
    26  //				On Ubuntu, if host does not have zip and unzip:
    27  //					$> sudo apt install zip
    28  //					$> sudo apt install unzip
    29  //				On Ubuntu, to install AWS CLI v2:
    30  //					$> curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
    31  //					$> unzip awscliv2.zip
    32  //					$> sudo ./aws/install
    33  //		2) $> aws configure set region awsRegionName --profile default
    34  // 		3) $> aws configure
    35  //				follow prompts to enter Access ID and Secret Key
    36  //
    37  // AWS Region Name Reference:
    38  //		us-west-2, us-east-1, ap-northeast-1, etc
    39  //		See: https://docs.aws.amazon.com/general/latest/gr/rande.html
    40  // =================================================================================================================
    41  
    42  import (
    43  	"bytes"
    44  	"context"
    45  	"encoding/base64"
    46  	"errors"
    47  	"fmt"
    48  	util "github.com/aldelo/common"
    49  	awshttp2 "github.com/aldelo/common/wrapper/aws"
    50  	"github.com/aldelo/common/wrapper/aws/awsregion"
    51  	"github.com/aldelo/common/wrapper/xray"
    52  	"github.com/aws/aws-sdk-go/aws"
    53  	"github.com/aws/aws-sdk-go/aws/awserr"
    54  	"github.com/aws/aws-sdk-go/aws/session"
    55  	"github.com/aws/aws-sdk-go/service/ses"
    56  	awsxray "github.com/aws/aws-xray-sdk-go/xray"
    57  	"mime/multipart"
    58  	"net/http"
    59  	"net/textproto"
    60  	"path/filepath"
    61  	"strings"
    62  	"time"
    63  )
    64  
    65  // ================================================================================================================
    66  // STRUCTS
    67  // ================================================================================================================
    68  
    69  // SES struct encapsulates the AWS SES access functionality
    70  type SES struct {
    71  	// define the AWS region that SES is located at
    72  	AwsRegion awsregion.AWSRegion
    73  
    74  	// custom http2 client options
    75  	HttpOptions *awshttp2.HttpClientSettings
    76  
    77  	// define configuration set to use if any
    78  	ConfigurationSetName string
    79  
    80  	// store ses client object
    81  	sesClient *ses.SES
    82  
    83  	_parentSegment *xray.XRayParentSegment
    84  }
    85  
    86  // Email struct encapsulates the email message definition to send via AWS SES
    87  type Email struct {
    88  	// required
    89  	From string
    90  
    91  	// at least one element is required
    92  	To []string
    93  
    94  	// optional
    95  	CC []string
    96  
    97  	// optional
    98  	BCC []string
    99  
   100  	// required
   101  	Subject string
   102  
   103  	// either BodyHtml or BodyText is required
   104  	BodyHtml string
   105  	BodyText string
   106  
   107  	// additional config info
   108  	ReturnPath string
   109  	ReplyTo    []string
   110  
   111  	// defaults to UTF-8 if left blank
   112  	Charset string
   113  }
   114  
   115  // SendQuota struct encapsulates the ses send quota definition
   116  type SendQuota struct {
   117  	Max24HourSendLimit    int
   118  	MaxPerSecondSendLimit int
   119  	SentLast24Hours       int
   120  }
   121  
   122  // EmailTarget defines a single email target contact for use with SendTemplateEmail or SendBulkTemplateEmail methods
   123  type EmailTarget struct {
   124  	// at least one element is required
   125  	To []string
   126  
   127  	// optional
   128  	CC []string
   129  
   130  	// optional
   131  	BCC []string
   132  
   133  	// required - template data in json
   134  	TemplateDataJson string
   135  }
   136  
   137  // BulkEmailMessageResult contains result of a bulk email
   138  type BulkEmailMessageResult struct {
   139  	MessageId string
   140  	Status    string
   141  	ErrorInfo string
   142  	Success   bool
   143  }
   144  
   145  // ================================================================================================================
   146  // STRUCTS FUNCTIONS
   147  // ================================================================================================================
   148  
   149  // ----------------------------------------------------------------------------------------------------------------
   150  // utility functions
   151  // ----------------------------------------------------------------------------------------------------------------
   152  
   153  // Connect will establish a connection to the SES service
   154  func (s *SES) Connect(parentSegment ...*xray.XRayParentSegment) (err error) {
   155  	if xray.XRayServiceOn() {
   156  		if len(parentSegment) > 0 {
   157  			s._parentSegment = parentSegment[0]
   158  		}
   159  
   160  		seg := xray.NewSegment("SES-Connect", s._parentSegment)
   161  		defer seg.Close()
   162  		defer func() {
   163  			_ = seg.Seg.AddMetadata("SES-AWS-Region", s.AwsRegion)
   164  
   165  			if err != nil {
   166  				_ = seg.Seg.AddError(err)
   167  			}
   168  		}()
   169  
   170  		err = s.connectInternal()
   171  
   172  		if err == nil {
   173  			awsxray.AWS(s.sesClient.Client)
   174  		}
   175  
   176  		return err
   177  	} else {
   178  		return s.connectInternal()
   179  	}
   180  }
   181  
   182  // connectInternal will establish a connection to the SES service
   183  func (s *SES) connectInternal() error {
   184  	// clean up prior object
   185  	s.sesClient = nil
   186  
   187  	if !s.AwsRegion.Valid() || s.AwsRegion == awsregion.UNKNOWN {
   188  		return errors.New("Connect To SES Failed: (AWS Session Error) " + "Region is Required")
   189  	}
   190  
   191  	// create custom http2 client if needed
   192  	var httpCli *http.Client
   193  	var httpErr error
   194  
   195  	if s.HttpOptions == nil {
   196  		s.HttpOptions = new(awshttp2.HttpClientSettings)
   197  	}
   198  
   199  	// use custom http2 client
   200  	h2 := &awshttp2.AwsHttp2Client{
   201  		Options: s.HttpOptions,
   202  	}
   203  
   204  	if httpCli, httpErr = h2.NewHttp2Client(); httpErr != nil {
   205  		return errors.New("Connect to SES Failed: (AWS Session Error) " + "Create Custom Http2 Client Errored = " + httpErr.Error())
   206  	}
   207  
   208  	// establish aws session connection and keep session object in struct
   209  	if sess, err := session.NewSession(
   210  		&aws.Config{
   211  			Region:     aws.String(s.AwsRegion.Key()),
   212  			HTTPClient: httpCli,
   213  		}); err != nil {
   214  		// aws session error
   215  		return errors.New("Connect To SES Failed: (AWS Session Error) " + err.Error())
   216  	} else {
   217  		// create cached objects for shared use
   218  		s.sesClient = ses.New(sess)
   219  
   220  		if s.sesClient == nil {
   221  			return errors.New("Connect To SES Client Failed: (New SES Client Connection) " + "Connection Object Nil")
   222  		}
   223  
   224  		// session stored to struct
   225  		return nil
   226  	}
   227  }
   228  
   229  // Disconnect will disjoin from aws session by clearing it
   230  func (s *SES) Disconnect() {
   231  	s.sesClient = nil
   232  }
   233  
   234  // UpdateParentSegment updates this struct's xray parent segment, if no parent segment, set nil
   235  func (s *SES) UpdateParentSegment(parentSegment *xray.XRayParentSegment) {
   236  	s._parentSegment = parentSegment
   237  }
   238  
   239  // ----------------------------------------------------------------------------------------------------------------
   240  // Email struct methods
   241  // ----------------------------------------------------------------------------------------------------------------
   242  
   243  // Initial sets new email message
   244  //
   245  // parameters:
   246  //
   247  //	from = email sender from address
   248  //	to = email sender to address
   249  //	subject = email subject text
   250  //	bodyText = email body content in text (both bodyText and bodyHtml may be set at the same time)
   251  //	bodyHtml = email body content in html (both bodyText and bodyHtml may be set at the same time)
   252  func (e *Email) Initial(from string, to string, subject string, bodyText string, bodyHtml ...string) *Email {
   253  	// set fields
   254  	e.From = from
   255  	e.To = append(e.To, to)
   256  	e.Subject = subject
   257  	e.BodyText = bodyText
   258  
   259  	// set body html
   260  	if len(bodyHtml) > 0 {
   261  		e.BodyHtml = bodyHtml[0]
   262  	}
   263  
   264  	// defaults
   265  	e.ReturnPath = from
   266  
   267  	if util.LenTrim(from) > 0 {
   268  		e.ReplyTo = append(e.ReplyTo, from)
   269  	}
   270  
   271  	e.Charset = "UTF-8"
   272  
   273  	return e
   274  }
   275  
   276  // SetTo adds additional 'To' addresses to email
   277  func (e *Email) SetTo(toAddress ...string) *Email {
   278  	if len(toAddress) > 0 {
   279  		for _, v := range toAddress {
   280  			e.To = append(e.To, v)
   281  		}
   282  	}
   283  
   284  	return e
   285  }
   286  
   287  // SetCC adds 'CC' addresses to email
   288  func (e *Email) SetCC(ccAddress ...string) *Email {
   289  	if len(ccAddress) > 0 {
   290  		for _, v := range ccAddress {
   291  			e.CC = append(e.CC, v)
   292  		}
   293  	}
   294  
   295  	return e
   296  }
   297  
   298  // SetBCC adds 'BCC' addresses to email
   299  func (e *Email) SetBCC(bccAddress ...string) *Email {
   300  	if len(bccAddress) > 0 {
   301  		for _, v := range bccAddress {
   302  			e.BCC = append(e.BCC, v)
   303  		}
   304  	}
   305  
   306  	return e
   307  }
   308  
   309  // SetReplyTo adds 'Reply-To' addresses to email
   310  func (e *Email) SetReplyTo(replyToAddress ...string) *Email {
   311  	if len(replyToAddress) > 0 {
   312  		for _, v := range replyToAddress {
   313  			e.ReplyTo = append(e.ReplyTo, v)
   314  		}
   315  	}
   316  
   317  	return e
   318  }
   319  
   320  // validateEmailFields will verify if the email fields are satisfied
   321  func (e *Email) validateEmailFields() error {
   322  	if util.LenTrim(e.From) <= 0 {
   323  		return errors.New("Verify Email Fields Failed: " + "From Address is Required")
   324  	}
   325  
   326  	if len(e.To) <= 0 {
   327  		return errors.New("Verify Email Fields Failed: " + "To Address is Required")
   328  	}
   329  
   330  	if util.LenTrim(e.Subject) <= 0 {
   331  		return errors.New("Verify Email Fields Failed: " + "Subject is Required")
   332  	}
   333  
   334  	if util.LenTrim(e.BodyHtml) <= 0 && util.LenTrim(e.BodyText) <= 0 {
   335  		return errors.New("Verify Email Fields Failed: " + "Body (Html or Text) is Required")
   336  	}
   337  
   338  	if util.LenTrim(e.Charset) <= 0 {
   339  		e.Charset = "UTF-8"
   340  	}
   341  
   342  	// validate successful
   343  	return nil
   344  }
   345  
   346  // GenerateSendEmailInput will create the SendEmailInput object from the struct fields
   347  func (e *Email) GenerateSendEmailInput() (*ses.SendEmailInput, error) {
   348  	// validate
   349  	if err := e.validateEmailFields(); err != nil {
   350  		return nil, err
   351  	}
   352  
   353  	// assemble SendEmailInput object
   354  	input := &ses.SendEmailInput{
   355  		Source: aws.String(e.From),
   356  		Destination: &ses.Destination{
   357  			ToAddresses: aws.StringSlice(e.To),
   358  		},
   359  		Message: &ses.Message{
   360  			Subject: &ses.Content{
   361  				Data:    aws.String(e.Subject),
   362  				Charset: aws.String(e.Charset),
   363  			},
   364  		},
   365  	}
   366  
   367  	// set cc and bcc if applicable
   368  	if len(e.CC) > 0 {
   369  		if input.Destination == nil {
   370  			input.Destination = new(ses.Destination)
   371  		}
   372  
   373  		input.Destination.CcAddresses = aws.StringSlice(e.CC)
   374  	}
   375  
   376  	if len(e.BCC) > 0 {
   377  		if input.Destination == nil {
   378  			input.Destination = new(ses.Destination)
   379  		}
   380  
   381  		input.Destination.BccAddresses = aws.StringSlice(e.BCC)
   382  	}
   383  
   384  	// set message body
   385  	if util.LenTrim(e.BodyHtml) > 0 {
   386  		if input.Message == nil {
   387  			input.Message = new(ses.Message)
   388  		}
   389  
   390  		if input.Message.Body == nil {
   391  			input.Message.Body = new(ses.Body)
   392  		}
   393  
   394  		if input.Message.Body.Html == nil {
   395  			input.Message.Body.Html = new(ses.Content)
   396  		}
   397  
   398  		input.Message.Body.Html.Data = aws.String(e.BodyHtml)
   399  		input.Message.Body.Html.Charset = aws.String(e.Charset)
   400  	}
   401  
   402  	if util.LenTrim(e.BodyText) > 0 {
   403  		if input.Message == nil {
   404  			input.Message = new(ses.Message)
   405  		}
   406  
   407  		if input.Message.Body == nil {
   408  			input.Message.Body = new(ses.Body)
   409  		}
   410  
   411  		if input.Message.Body.Text == nil {
   412  			input.Message.Body.Text = new(ses.Content)
   413  		}
   414  
   415  		input.Message.Body.Text.Data = aws.String(e.BodyText)
   416  		input.Message.Body.Text.Charset = aws.String(e.Charset)
   417  	}
   418  
   419  	if util.LenTrim(e.ReturnPath) > 0 {
   420  		input.ReturnPath = aws.String(e.ReturnPath)
   421  	}
   422  
   423  	if len(e.ReplyTo) > 0 {
   424  		input.ReplyToAddresses = aws.StringSlice(e.ReplyTo)
   425  	}
   426  
   427  	// return result
   428  	return input, nil
   429  }
   430  
   431  // GenerateSendRawEmailInput will create the SendRawEmailInput object from the struct fields
   432  //
   433  // attachmentContentType = See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
   434  func (e *Email) GenerateSendRawEmailInput(attachmentFileName string, attachmentContentType string, attachmentData []byte) (*ses.SendRawEmailInput, error) {
   435  	// validate
   436  	if err := e.validateEmailFields(); err != nil {
   437  		return nil, err
   438  	}
   439  
   440  	buf := new(bytes.Buffer)
   441  	writer := multipart.NewWriter(buf)
   442  
   443  	// email main header
   444  	h := make(textproto.MIMEHeader)
   445  	h.Set("From", e.From)
   446  	h.Set("To", util.SliceStringToCSVString(e.To, false))
   447  
   448  	if len(e.CC) > 0 {
   449  		h.Set("CC", util.SliceStringToCSVString(e.CC, false))
   450  	}
   451  
   452  	if len(e.BCC) > 0 {
   453  		h.Set("BCC", util.SliceStringToCSVString(e.BCC, false))
   454  	}
   455  
   456  	if util.LenTrim(e.ReturnPath) > 0 {
   457  		h.Set("Return-Path", e.ReturnPath)
   458  	}
   459  
   460  	if len(e.ReplyTo) > 0 {
   461  		h.Set("Reply-To", e.ReplyTo[0])
   462  	}
   463  
   464  	h.Set("Subject", e.Subject)
   465  	h.Set("Content-Language", "en-US")
   466  	h.Set("Content-Type", "multipart/mixed; boundary=\""+writer.Boundary()+"\"")
   467  	h.Set("MIME-Version", "1.0")
   468  
   469  	if _, err := writer.CreatePart(h); err != nil {
   470  		return nil, err
   471  	}
   472  
   473  	charset := "UTF-8"
   474  
   475  	if util.LenTrim(e.Charset) > 0 {
   476  		charset = e.Charset
   477  	}
   478  
   479  	// email body - plain text
   480  	if util.LenTrim(e.BodyText) > 0 {
   481  		h = make(textproto.MIMEHeader)
   482  		h.Set("Content-Transfer-Encoding", "quoted-printable")
   483  		h.Set("Content-Type", "text/plain; charset="+charset)
   484  		part, err := writer.CreatePart(h)
   485  		if err != nil {
   486  			return nil, err
   487  		}
   488  
   489  		if _, err = part.Write([]byte(e.BodyText)); err != nil {
   490  			return nil, err
   491  		}
   492  	}
   493  
   494  	// email body - html text
   495  	if util.LenTrim(e.BodyHtml) > 0 {
   496  		h = make(textproto.MIMEHeader)
   497  		h.Set("Content-Transfer-Encoding", "quoted-printable")
   498  		h.Set("Content-Type", "text/html; charset="+charset)
   499  		partH, err := writer.CreatePart(h)
   500  		if err != nil {
   501  			return nil, err
   502  		}
   503  
   504  		if _, err = partH.Write([]byte(e.BodyHtml)); err != nil {
   505  			return nil, err
   506  		}
   507  	}
   508  
   509  	// file attachment
   510  	if util.LenTrim(attachmentFileName) > 0 {
   511  		fn := filepath.Base(attachmentFileName)
   512  
   513  		h = make(textproto.MIMEHeader)
   514  		// h.Set("Content-Disposition", "attachment; filename="+fn)
   515  		h.Set("Content-Type", attachmentContentType+"; name=\""+fn+"\"")
   516  		h.Set("Content-Description", fn)
   517  		h.Set("Content-Disposition", "attachment; filename=\""+fn+"\"; size="+util.Itoa(len(attachmentData))+";")
   518  		h.Set("Content-Transfer-Encoding", "base64")
   519  
   520  		partA, err := writer.CreatePart(h)
   521  		if err != nil {
   522  			return nil, err
   523  		}
   524  
   525  		// must base64 encode first before write
   526  		if _, err = partA.Write([]byte(base64.StdEncoding.EncodeToString(attachmentData))); err != nil {
   527  			return nil, err
   528  		}
   529  	}
   530  
   531  	// clean up
   532  	if err := writer.Close(); err != nil {
   533  		return nil, err
   534  	}
   535  
   536  	// strip boundary line before header
   537  	s := buf.String()
   538  
   539  	if strings.Count(s, "\n") < 2 {
   540  		return nil, fmt.Errorf("Email Content Not Valid")
   541  	}
   542  
   543  	s = strings.SplitN(s, "\n", 2)[1]
   544  
   545  	raw := ses.RawMessage{
   546  		Data: []byte(s),
   547  	}
   548  
   549  	// assemble SendRawEmailInput object
   550  	input := &ses.SendRawEmailInput{
   551  		Destinations: aws.StringSlice(e.To),
   552  		Source:       aws.String(e.From),
   553  		RawMessage:   &raw,
   554  	}
   555  
   556  	// return result
   557  	return input, nil
   558  }
   559  
   560  // ----------------------------------------------------------------------------------------------------------------
   561  // EmailTarget struct methods
   562  // ----------------------------------------------------------------------------------------------------------------
   563  
   564  // Initial will set template data in json, and list of toAddresses variadic
   565  func (t *EmailTarget) Initial(templateDataJson string, toAddress ...string) *EmailTarget {
   566  	t.TemplateDataJson = templateDataJson
   567  
   568  	if len(toAddress) > 0 {
   569  		for _, v := range toAddress {
   570  			t.To = append(t.To, v)
   571  		}
   572  	}
   573  
   574  	return t
   575  }
   576  
   577  // SetCC will set list of ccAddress variadic to EmailTarget
   578  func (t *EmailTarget) SetCC(ccAddress ...string) *EmailTarget {
   579  	if len(ccAddress) > 0 {
   580  		for _, v := range ccAddress {
   581  			t.CC = append(t.CC, v)
   582  		}
   583  	}
   584  
   585  	return t
   586  }
   587  
   588  // SetBCC will set list of bccAddress variadic to EmailTarget
   589  func (t *EmailTarget) SetBCC(bccAddress ...string) *EmailTarget {
   590  	if len(bccAddress) > 0 {
   591  		for _, v := range bccAddress {
   592  			t.BCC = append(t.BCC, v)
   593  		}
   594  	}
   595  
   596  	return t
   597  }
   598  
   599  // ----------------------------------------------------------------------------------------------------------------
   600  // SES general methods
   601  // ----------------------------------------------------------------------------------------------------------------
   602  
   603  // handleSESError will evaluate the error and return the revised error object
   604  func (s *SES) handleSESError(err error) error {
   605  	if err != nil {
   606  		if aerr, ok := err.(awserr.Error); ok {
   607  			// aws error
   608  			return errors.New("[AWS] " + aerr.Code() + " - " + aerr.Message())
   609  		} else {
   610  			// other error
   611  			return errors.New("[General] " + err.Error())
   612  		}
   613  	} else {
   614  		return nil
   615  	}
   616  }
   617  
   618  // GetSendQuota will get the ses send quota
   619  func (s *SES) GetSendQuota(timeOutDuration ...time.Duration) (sq *SendQuota, err error) {
   620  	segCtx := context.Background()
   621  	segCtxSet := false
   622  
   623  	seg := xray.NewSegmentNullable("SES-GetSendQuota", s._parentSegment)
   624  
   625  	if seg != nil {
   626  		segCtx = seg.Ctx
   627  		segCtxSet = true
   628  
   629  		defer seg.Close()
   630  		defer func() {
   631  			_ = seg.Seg.AddMetadata("SES-GetSendQuota-Result-SendQuota", sq)
   632  
   633  			if err != nil {
   634  				_ = seg.Seg.AddError(err)
   635  			}
   636  		}()
   637  	}
   638  
   639  	// validate
   640  	if s.sesClient == nil {
   641  		err = errors.New("GetSendQuota Failed: " + "SES Client is Required")
   642  		return nil, err
   643  	}
   644  
   645  	// compose input
   646  	input := &ses.GetSendQuotaInput{}
   647  
   648  	// get send quota from ses
   649  	var output *ses.GetSendQuotaOutput
   650  
   651  	if len(timeOutDuration) > 0 {
   652  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   653  		defer cancel()
   654  
   655  		output, err = s.sesClient.GetSendQuotaWithContext(ctx, input)
   656  	} else {
   657  		if segCtxSet {
   658  			output, err = s.sesClient.GetSendQuotaWithContext(segCtx, input)
   659  		} else {
   660  			output, err = s.sesClient.GetSendQuota(input)
   661  		}
   662  	}
   663  
   664  	// evaluate result
   665  	if err != nil {
   666  		err = errors.New("GetSendQuota Failed: " + err.Error())
   667  		return nil, err
   668  	}
   669  
   670  	sq = &SendQuota{
   671  		Max24HourSendLimit:    util.Float64ToInt(*output.Max24HourSend),
   672  		MaxPerSecondSendLimit: util.Float64ToInt(*output.MaxSendRate),
   673  		SentLast24Hours:       util.Float64ToInt(*output.SentLast24Hours),
   674  	}
   675  
   676  	return sq, nil
   677  }
   678  
   679  // SendEmail will send an email message out via SES
   680  func (s *SES) SendEmail(email *Email, timeOutDuration ...time.Duration) (messageId string, err error) {
   681  	segCtx := context.Background()
   682  	segCtxSet := false
   683  
   684  	seg := xray.NewSegmentNullable("SES-SendEmail", s._parentSegment)
   685  
   686  	if seg != nil {
   687  		segCtx = seg.Ctx
   688  		segCtxSet = true
   689  
   690  		defer seg.Close()
   691  		defer func() {
   692  			if email != nil {
   693  				_ = seg.Seg.AddMetadata("SES-SendEmail-Email-From", email.From)
   694  				_ = seg.Seg.AddMetadata("SES-SendEmail-Email-To", email.To)
   695  				_ = seg.Seg.AddMetadata("SES-SendEmail-Email-Subject", email.Subject)
   696  				_ = seg.Seg.AddMetadata("SES-SendEmail-Result-MessageID", messageId)
   697  			} else {
   698  				_ = seg.Seg.AddMetadata("SES-SendEmail-Email-Fail", "Email Object Nil")
   699  			}
   700  
   701  			if err != nil {
   702  				_ = seg.Seg.AddError(err)
   703  			}
   704  		}()
   705  	}
   706  
   707  	// validate
   708  	if s.sesClient == nil {
   709  		err = errors.New("SendEmail Failed: " + "SES Client is Required")
   710  		return "", err
   711  	}
   712  
   713  	if email == nil {
   714  		err = errors.New("SendEmail Failed: " + "Email Object is Required")
   715  		return "", err
   716  	}
   717  
   718  	// generate email input
   719  	var input *ses.SendEmailInput
   720  	input, err = email.GenerateSendEmailInput()
   721  
   722  	if err != nil {
   723  		err = errors.New("SendEmail Failed: " + err.Error())
   724  		return "", err
   725  	}
   726  
   727  	if input == nil {
   728  		err = errors.New("SendEmail Failed: " + "SendEmailInput is Nil")
   729  		return "", err
   730  	}
   731  
   732  	// set configurationSetName if applicable
   733  	if util.LenTrim(s.ConfigurationSetName) > 0 {
   734  		input.ConfigurationSetName = aws.String(s.ConfigurationSetName)
   735  	}
   736  
   737  	// send out email
   738  	var output *ses.SendEmailOutput
   739  
   740  	if len(timeOutDuration) > 0 {
   741  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   742  		defer cancel()
   743  
   744  		output, err = s.sesClient.SendEmailWithContext(ctx, input)
   745  	} else {
   746  		if segCtxSet {
   747  			output, err = s.sesClient.SendEmailWithContext(segCtx, input)
   748  		} else {
   749  			output, err = s.sesClient.SendEmail(input)
   750  		}
   751  	}
   752  
   753  	// evaluate output
   754  	if err != nil {
   755  		if err = s.handleSESError(err); err != nil {
   756  			return "", err
   757  		}
   758  	}
   759  
   760  	// email sent successfully
   761  	messageId = aws.StringValue(output.MessageId)
   762  	return messageId, nil
   763  }
   764  
   765  // SendRawEmail will send an raw email message out via SES, supporting attachments
   766  //
   767  // attachmentContentType = See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
   768  func (s *SES) SendRawEmail(email *Email, attachmentFileName string, attachmentContentType string,
   769  	timeOutDuration ...time.Duration) (messageId string, err error) {
   770  	segCtx := context.Background()
   771  	segCtxSet := false
   772  
   773  	seg := xray.NewSegmentNullable("SES-SendRawEmail", s._parentSegment)
   774  
   775  	if seg != nil {
   776  		segCtx = seg.Ctx
   777  		segCtxSet = true
   778  
   779  		defer seg.Close()
   780  		defer func() {
   781  			if email != nil {
   782  				_ = seg.Seg.AddMetadata("SES-SendRawEmail-Email-From", email.From)
   783  				_ = seg.Seg.AddMetadata("SES-SendRawEmail-Email-To", email.To)
   784  				_ = seg.Seg.AddMetadata("SES-SendRawEmail-Email-Subject", email.Subject)
   785  				_ = seg.Seg.AddMetadata("SES-SendRawEmail-Email-Attachment-FileName", attachmentFileName)
   786  				_ = seg.Seg.AddMetadata("SES-SendRawEmail-Email-Attachment-ContentType", attachmentContentType)
   787  				_ = seg.Seg.AddMetadata("SES-SendRawEmail-Result-MessageID", messageId)
   788  			} else {
   789  				_ = seg.Seg.AddMetadata("SES-SendRawEmail-Email-Fail", "Email Object Nil")
   790  			}
   791  
   792  			if err != nil {
   793  				_ = seg.Seg.AddError(err)
   794  			}
   795  		}()
   796  	}
   797  
   798  	// validate
   799  	if s.sesClient == nil {
   800  		err = errors.New("SendRawEmail Failed: " + "SES Client is Required")
   801  		return "", err
   802  	}
   803  
   804  	if email == nil {
   805  		err = errors.New("SendRawEmail Failed: " + "Email Object is Required")
   806  		return "", err
   807  	}
   808  
   809  	// load attachment info
   810  	attachmentData := []byte{}
   811  
   812  	if util.LenTrim(attachmentFileName) > 0 {
   813  		if attachmentData, err = util.FileReadBytes(attachmentFileName); err != nil {
   814  			err = fmt.Errorf("SendRawEmail Failed: (Load Attachment File '"+attachmentFileName+"' Error)", err)
   815  			return "", err
   816  		} else {
   817  			if len(attachmentData) == 0 {
   818  				err = fmt.Errorf("SendRawEmail Failed: ", "Attachment Data From File is Empty")
   819  				return "", err
   820  			}
   821  
   822  			if util.LenTrim(attachmentContentType) == 0 {
   823  				err = fmt.Errorf("SendRawEmail Failed: ", "Attachment Content-Type is Required")
   824  				return "", err
   825  			}
   826  		}
   827  	} else {
   828  		attachmentFileName = ""
   829  		attachmentContentType = ""
   830  	}
   831  
   832  	// generate email input
   833  	var input *ses.SendRawEmailInput
   834  	input, err = email.GenerateSendRawEmailInput(attachmentFileName, attachmentContentType, attachmentData)
   835  
   836  	if err != nil {
   837  		err = errors.New("SendRawEmail Failed: " + err.Error())
   838  		return "", err
   839  	}
   840  
   841  	if input == nil {
   842  		err = errors.New("SendRawEmail Failed: " + "SendRawEmailInput is Nil")
   843  		return "", err
   844  	}
   845  
   846  	// set configurationSetName if applicable
   847  	if util.LenTrim(s.ConfigurationSetName) > 0 {
   848  		input.ConfigurationSetName = aws.String(s.ConfigurationSetName)
   849  	}
   850  
   851  	// send out email
   852  	var output *ses.SendRawEmailOutput
   853  
   854  	if len(timeOutDuration) > 0 {
   855  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   856  		defer cancel()
   857  
   858  		output, err = s.sesClient.SendRawEmailWithContext(ctx, input)
   859  	} else {
   860  		if segCtxSet {
   861  			output, err = s.sesClient.SendRawEmailWithContext(segCtx, input)
   862  		} else {
   863  			output, err = s.sesClient.SendRawEmail(input)
   864  		}
   865  	}
   866  
   867  	// evaluate output
   868  	if err != nil {
   869  		if err = s.handleSESError(err); err != nil {
   870  			return "", err
   871  		}
   872  	}
   873  
   874  	// email sent successfully
   875  	messageId = aws.StringValue(output.MessageId)
   876  	return messageId, nil
   877  }
   878  
   879  // ----------------------------------------------------------------------------------------------------------------
   880  // SES template & bulk email methods
   881  // ----------------------------------------------------------------------------------------------------------------
   882  
   883  // CreateTemplate will create an email template for use with SendTemplateEmail and SendBulkTemplateEmail methods
   884  //
   885  // parameters:
   886  //  1. templateName = name of the template, must be unique
   887  //  2. subjectPart = subject text with tag name value replacements
   888  //  3. textPart = body text with tag name value replacements
   889  //  4. htmlPart = body html with tag name value replacements
   890  //  5. timeOutDuration = optional time out value to use in context
   891  //
   892  // template tokens:
   893  //  1. subjectPart, textPart, htmlPart = may contain Tag Names for personalization
   894  //  2. Tag Name = using {{tagName}} within the string defined above in #1
   895  //  3. example:
   896  //     a) Greetings, {{name}}
   897  //     b) <h1>hello {{name}}, how are you</h1><p>Today is {{dayOfWeek}}</p>
   898  //     c) <html><head></head><body><h1>hello {{name}}, how are you</h1><p>Today is {{dayOfWeek}}</p></body></html>
   899  //  4. when sending template mail, the Tag Name values are replaced via key-Value pairs within TemplateData in SendTemplateEmail and SendBulkTemplateEmail methods:
   900  //     a) { "name":"Harry", "dayOfWeek":"Monday" }
   901  func (s *SES) CreateTemplate(templateName string, subjectPart string, textPart string, htmlPart string, timeOutDuration ...time.Duration) (err error) {
   902  	segCtx := context.Background()
   903  	segCtxSet := false
   904  
   905  	seg := xray.NewSegmentNullable("SES-CreateTemplate", s._parentSegment)
   906  
   907  	if seg != nil {
   908  		segCtx = seg.Ctx
   909  		segCtxSet = true
   910  
   911  		defer seg.Close()
   912  		defer func() {
   913  			_ = seg.Seg.AddMetadata("SES-CreateTemplate-TemplateName", templateName)
   914  			_ = seg.Seg.AddMetadata("SES-CreateTemplate-SubjectPart", subjectPart)
   915  			_ = seg.Seg.AddMetadata("SES-CreateTemplate-TextPart", textPart)
   916  			_ = seg.Seg.AddMetadata("SES-CreateTemplate-HtmlPart", htmlPart)
   917  
   918  			if err != nil {
   919  				_ = seg.Seg.AddError(err)
   920  			}
   921  		}()
   922  	}
   923  
   924  	// validate
   925  	if s.sesClient == nil {
   926  		err = errors.New("CreateTemplate Failed: " + "SES Client is Required")
   927  		return err
   928  	}
   929  
   930  	if util.LenTrim(templateName) <= 0 {
   931  		err = errors.New("CreateTemplate Failed: " + "Template Name is Required")
   932  		return err
   933  	}
   934  
   935  	if util.LenTrim(subjectPart) <= 0 {
   936  		err = errors.New("CreateTemplate Failed: " + "Subject Part is Required")
   937  		return err
   938  	}
   939  
   940  	if util.LenTrim(textPart) <= 0 && util.LenTrim(htmlPart) <= 0 {
   941  		err = errors.New("CreateTemplate Failed: " + "Text or Html Part is Required")
   942  		return err
   943  	}
   944  
   945  	// create input object
   946  	input := &ses.CreateTemplateInput{
   947  		Template: &ses.Template{
   948  			TemplateName: aws.String(templateName),
   949  			SubjectPart:  aws.String(subjectPart),
   950  		},
   951  	}
   952  
   953  	if util.LenTrim(textPart) > 0 {
   954  		input.Template.TextPart = aws.String(textPart)
   955  	}
   956  
   957  	if util.LenTrim(htmlPart) > 0 {
   958  		input.Template.HtmlPart = aws.String(htmlPart)
   959  	}
   960  
   961  	// create template action
   962  	if len(timeOutDuration) > 0 {
   963  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
   964  		defer cancel()
   965  
   966  		_, err = s.sesClient.CreateTemplateWithContext(ctx, input)
   967  	} else {
   968  		if segCtxSet {
   969  			_, err = s.sesClient.CreateTemplateWithContext(segCtx, input)
   970  		} else {
   971  			_, err = s.sesClient.CreateTemplate(input)
   972  		}
   973  	}
   974  
   975  	// evaluate result
   976  	if err != nil {
   977  		// failure
   978  		err = errors.New("CreateTemplate Failed: (Create Template Action) " + err.Error())
   979  		return err
   980  	} else {
   981  		// success
   982  		return nil
   983  	}
   984  }
   985  
   986  // UpdateTemplate will update an existing email template for use with SendTemplateEmail and SendBulkTemplateEmail methods
   987  //
   988  // parameters:
   989  //  1. templateName = name of the template, must be unique
   990  //  2. subjectPart = subject text with tag name value replacements
   991  //  3. textPart = body text with tag name value replacements
   992  //  4. htmlPart = body html with tag name value replacements
   993  //  5. timeOutDuration = optional time out value to use in context
   994  //
   995  // template tokens:
   996  //  1. subjectPart, textPart, htmlPart = may contain Tag Names for personalization
   997  //  2. Tag Name = using {{tagName}} within the string defined above in #1
   998  //  3. example:
   999  //     a) Greetings, {{name}}
  1000  //     b) <h1>hello {{name}}, how are you</h1><p>Today is {{dayOfWeek}}</p>
  1001  //     c) <html><head></head><body><h1>hello {{name}}, how are you</h1><p>Today is {{dayOfWeek}}</p></body></html>
  1002  //  4. when sending template mail, the Tag Name values are replaced via key-Value pairs within TemplateData in SendTemplateEmail and SendBulkTemplateEmail methods:
  1003  //     a) { "name":"Harry", "dayOfWeek":"Monday" }
  1004  func (s *SES) UpdateTemplate(templateName string, subjectPart string, textPart string, htmlPart string, timeOutDuration ...time.Duration) (err error) {
  1005  	segCtx := context.Background()
  1006  	segCtxSet := false
  1007  
  1008  	seg := xray.NewSegmentNullable("SES-UpdateTemplate", s._parentSegment)
  1009  
  1010  	if seg != nil {
  1011  		segCtx = seg.Ctx
  1012  		segCtxSet = true
  1013  
  1014  		defer seg.Close()
  1015  		defer func() {
  1016  			_ = seg.Seg.AddMetadata("SES-UpdateTemplate-TemplateName", templateName)
  1017  			_ = seg.Seg.AddMetadata("SES-UpdateTemplate-SubjectPart", subjectPart)
  1018  			_ = seg.Seg.AddMetadata("SES-UpdateTemplate-TextPart", textPart)
  1019  			_ = seg.Seg.AddMetadata("SES-UpdateTemplate-HtmlPart", htmlPart)
  1020  
  1021  			if err != nil {
  1022  				_ = seg.Seg.AddError(err)
  1023  			}
  1024  		}()
  1025  	}
  1026  
  1027  	// validate
  1028  	if s.sesClient == nil {
  1029  		err = errors.New("UpdateTemplate Failed: " + "SES Client is Required")
  1030  		return err
  1031  	}
  1032  
  1033  	if util.LenTrim(templateName) <= 0 {
  1034  		err = errors.New("UpdateTemplate Failed: " + "Template Name is Required")
  1035  		return err
  1036  	}
  1037  
  1038  	if util.LenTrim(subjectPart) <= 0 {
  1039  		err = errors.New("UpdateTemplate Failed: " + "Subject Part is Required")
  1040  		return err
  1041  	}
  1042  
  1043  	if util.LenTrim(textPart) <= 0 && util.LenTrim(htmlPart) <= 0 {
  1044  		err = errors.New("UpdateTemplate Failed: " + "Text or Html Part is Required")
  1045  		return err
  1046  	}
  1047  
  1048  	// create input object
  1049  	input := &ses.UpdateTemplateInput{
  1050  		Template: &ses.Template{
  1051  			TemplateName: aws.String(templateName),
  1052  			SubjectPart:  aws.String(subjectPart),
  1053  		},
  1054  	}
  1055  
  1056  	if util.LenTrim(textPart) > 0 {
  1057  		input.Template.TextPart = aws.String(textPart)
  1058  	}
  1059  
  1060  	if util.LenTrim(htmlPart) > 0 {
  1061  		input.Template.HtmlPart = aws.String(htmlPart)
  1062  	}
  1063  
  1064  	// update template action
  1065  	if len(timeOutDuration) > 0 {
  1066  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1067  		defer cancel()
  1068  
  1069  		_, err = s.sesClient.UpdateTemplateWithContext(ctx, input)
  1070  	} else {
  1071  		if segCtxSet {
  1072  			_, err = s.sesClient.UpdateTemplateWithContext(segCtx, input)
  1073  		} else {
  1074  			_, err = s.sesClient.UpdateTemplate(input)
  1075  		}
  1076  	}
  1077  
  1078  	// evaluate result
  1079  	if err != nil {
  1080  		// failure
  1081  		err = errors.New("UpdateTemplate Failed: (Update Template Action) " + err.Error())
  1082  		return err
  1083  	} else {
  1084  		// success
  1085  		return nil
  1086  	}
  1087  }
  1088  
  1089  // DeleteTemplate will delete an existing email template
  1090  //
  1091  // parameters:
  1092  //  1. templateName = name of the template to delete
  1093  //  2. timeOutDuration = optional time out value to use in context
  1094  func (s *SES) DeleteTemplate(templateName string, timeOutDuration ...time.Duration) (err error) {
  1095  	segCtx := context.Background()
  1096  	segCtxSet := false
  1097  
  1098  	seg := xray.NewSegmentNullable("SES-DeleteTemplate", s._parentSegment)
  1099  
  1100  	if seg != nil {
  1101  		segCtx = seg.Ctx
  1102  		segCtxSet = true
  1103  
  1104  		defer seg.Close()
  1105  		defer func() {
  1106  			_ = seg.Seg.AddMetadata("SES-DeleteTemplate-TemplateName", templateName)
  1107  
  1108  			if err != nil {
  1109  				_ = seg.Seg.AddError(err)
  1110  			}
  1111  		}()
  1112  	}
  1113  
  1114  	// validate
  1115  	if s.sesClient == nil {
  1116  		err = errors.New("DeleteTemplate Failed: " + "SES Client is Required")
  1117  		return err
  1118  	}
  1119  
  1120  	if util.LenTrim(templateName) <= 0 {
  1121  		err = errors.New("DeleteTemplate Failed: " + "Template Name is Required")
  1122  		return err
  1123  	}
  1124  
  1125  	// create input object
  1126  	input := &ses.DeleteTemplateInput{
  1127  		TemplateName: aws.String(templateName),
  1128  	}
  1129  
  1130  	// update template action
  1131  	if len(timeOutDuration) > 0 {
  1132  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1133  		defer cancel()
  1134  
  1135  		_, err = s.sesClient.DeleteTemplateWithContext(ctx, input)
  1136  	} else {
  1137  		if segCtxSet {
  1138  			_, err = s.sesClient.DeleteTemplateWithContext(segCtx, input)
  1139  		} else {
  1140  			_, err = s.sesClient.DeleteTemplate(input)
  1141  		}
  1142  	}
  1143  
  1144  	// evaluate result
  1145  	if err != nil {
  1146  		// failure
  1147  		err = errors.New("DeleteTemplate Failed: (Delete Template Action) " + err.Error())
  1148  		return err
  1149  	} else {
  1150  		// success
  1151  		return nil
  1152  	}
  1153  }
  1154  
  1155  // SendTemplateEmail will send out email via ses using template
  1156  //
  1157  // parameters:
  1158  //  1. senderEmail = sender's email address
  1159  //  2. returnPath = optional, email return path address
  1160  //  3. replyTo = optional, email reply to address
  1161  //  4. templateName = the name of the template to use for sending out template emails
  1162  //  5. emailTarget = pointer to email target object defining where the email is sent to, along with template data key value pairs in json
  1163  //  6. timeOutDuration = optional, time out value to use in context
  1164  //
  1165  // template tokens:
  1166  //  1. subjectPart, textPart, htmlPart = may contain Tag Names for personalization
  1167  //  2. Tag Name = using {{tagName}} within the string defined above in #1
  1168  //  3. example:
  1169  //     a) Greetings, {{name}}
  1170  //     b) <h1>hello {{name}}, how are you</h1><p>Today is {{dayOfWeek}}</p>
  1171  //     c) <html><head></head><body><h1>hello {{name}}, how are you</h1><p>Today is {{dayOfWeek}}</p></body></html>
  1172  //  4. when sending template mail, the Tag Name values are replaced via key-Value pairs within TemplateData in SendTemplateEmail and SendBulkTemplateEmail methods:
  1173  //     a) { "name":"Harry", "dayOfWeek":"Monday" }
  1174  //
  1175  // notes:
  1176  //
  1177  //	a) Template = name of template to apply to the email
  1178  //	b) TemplateData = json string holding key-value pair of Tag Name and Tag Value (see below about template tokens)
  1179  //	c) Source = email address of sender
  1180  //	d) ReturnPath = return email address (usually same as source)
  1181  //	e) ReplyToAddresses = list of email addresses for email reply to
  1182  //	f) Destination = email send to destination
  1183  //	g) ConfigurationSetName = if ses has a set defined, and need to be used herein
  1184  func (s *SES) SendTemplateEmail(senderEmail string,
  1185  	returnPath string,
  1186  	replyTo string,
  1187  	templateName string,
  1188  	emailTarget *EmailTarget,
  1189  	timeOutDuration ...time.Duration) (messageId string, err error) {
  1190  	segCtx := context.Background()
  1191  	segCtxSet := false
  1192  
  1193  	seg := xray.NewSegmentNullable("SES-SendTemplateEmail", s._parentSegment)
  1194  
  1195  	if seg != nil {
  1196  		segCtx = seg.Ctx
  1197  		segCtxSet = true
  1198  
  1199  		defer seg.Close()
  1200  		defer func() {
  1201  			_ = seg.Seg.AddMetadata("SES-SendTemplateEmail-Email-From", senderEmail)
  1202  			_ = seg.Seg.AddMetadata("SES-SendTemplateEmail-Email-ReturnPath", returnPath)
  1203  			_ = seg.Seg.AddMetadata("SES-SendTemplateEmail-Email-ReplyTo", replyTo)
  1204  			_ = seg.Seg.AddMetadata("SES-SendTemplateEmail-TemplateName", templateName)
  1205  
  1206  			if emailTarget != nil {
  1207  				_ = seg.Seg.AddMetadata("SES-SendTemplateEmail-Email-To", emailTarget.To)
  1208  				_ = seg.Seg.AddMetadata("SES-SendTemplateEmail-Result-MessageID", messageId)
  1209  			} else {
  1210  				_ = seg.Seg.AddMetadata("SES-SendTemplateEmail-Email-Fail", "Email Target Nil")
  1211  			}
  1212  
  1213  			if err != nil {
  1214  				_ = seg.Seg.AddError(err)
  1215  			}
  1216  		}()
  1217  	}
  1218  
  1219  	// validate
  1220  	if s.sesClient == nil {
  1221  		err = errors.New("SendTemplateEmail Failed: " + "SES Client is Required")
  1222  		return "", err
  1223  	}
  1224  
  1225  	if util.LenTrim(senderEmail) <= 0 {
  1226  		err = errors.New("SendTemplateEmail Failed: " + "Sender Email is Required")
  1227  		return "", err
  1228  	}
  1229  
  1230  	if util.LenTrim(templateName) <= 0 {
  1231  		err = errors.New("SendTemplateEmail Failed: " + "Template Name is Required")
  1232  		return "", err
  1233  	}
  1234  
  1235  	if emailTarget == nil {
  1236  		err = errors.New("SendTemplateEmail Failed: " + "Email Target is Required (Nil)")
  1237  		return "", err
  1238  	}
  1239  
  1240  	if len(emailTarget.To) <= 0 {
  1241  		err = errors.New("SendTemplateEmail Failed: " + "Email Target's To-Address is Required")
  1242  		return "", err
  1243  	}
  1244  
  1245  	// create input object
  1246  	input := &ses.SendTemplatedEmailInput{
  1247  		Template: aws.String(templateName),
  1248  		Source:   aws.String(senderEmail),
  1249  	}
  1250  
  1251  	// set additional input values
  1252  	if util.LenTrim(returnPath) > 0 {
  1253  		input.ReturnPath = aws.String(returnPath)
  1254  	} else {
  1255  		input.ReturnPath = aws.String(senderEmail)
  1256  	}
  1257  
  1258  	if util.LenTrim(replyTo) > 0 {
  1259  		input.ReplyToAddresses = []*string{aws.String(replyTo)}
  1260  	} else {
  1261  		input.ReplyToAddresses = []*string{aws.String(senderEmail)}
  1262  	}
  1263  
  1264  	if input.Destination == nil {
  1265  		input.Destination = new(ses.Destination)
  1266  	}
  1267  
  1268  	if len(emailTarget.To) > 0 {
  1269  		input.Destination.ToAddresses = aws.StringSlice(emailTarget.To)
  1270  	}
  1271  
  1272  	if len(emailTarget.CC) > 0 {
  1273  		input.Destination.CcAddresses = aws.StringSlice(emailTarget.CC)
  1274  	}
  1275  
  1276  	if len(emailTarget.BCC) > 0 {
  1277  		input.Destination.BccAddresses = aws.StringSlice(emailTarget.BCC)
  1278  	}
  1279  
  1280  	if util.LenTrim(emailTarget.TemplateDataJson) > 0 {
  1281  		input.TemplateData = aws.String(emailTarget.TemplateDataJson)
  1282  	}
  1283  
  1284  	if util.LenTrim(s.ConfigurationSetName) > 0 {
  1285  		input.ConfigurationSetName = aws.String(s.ConfigurationSetName)
  1286  	}
  1287  
  1288  	// perform action
  1289  	var output *ses.SendTemplatedEmailOutput
  1290  
  1291  	if len(timeOutDuration) > 0 {
  1292  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1293  		defer cancel()
  1294  
  1295  		output, err = s.sesClient.SendTemplatedEmailWithContext(ctx, input)
  1296  	} else {
  1297  		if segCtxSet {
  1298  			output, err = s.sesClient.SendTemplatedEmailWithContext(segCtx, input)
  1299  		} else {
  1300  			output, err = s.sesClient.SendTemplatedEmail(input)
  1301  		}
  1302  	}
  1303  
  1304  	// evaluate result
  1305  	if err != nil {
  1306  		err = errors.New("SendTemplateEmailFailed: (Send Action) " + err.Error())
  1307  		return "", err
  1308  	} else {
  1309  		messageId = *output.MessageId
  1310  		return messageId, nil
  1311  	}
  1312  }
  1313  
  1314  // SendBulkTemplateEmail will send out bulk email via ses using template
  1315  //
  1316  // parameters:
  1317  //  1. senderEmail = sender's email address
  1318  //  2. returnPath = optional, email return path address
  1319  //  3. replyTo = optional, email reply to address
  1320  //  4. templateName = the name of the template to use for sending out template emails
  1321  //  5. defaultTemplateDataJson = the default template data key value pairs in json, to be used if emailTarget did not define a template data json
  1322  //  6. emailTargetList = slice of pointer to email target object defining where the email is sent to, along with template data key value pairs in json
  1323  //  7. timeOutDuration = optional, time out value to use in context
  1324  //
  1325  // template tokens:
  1326  //  1. subjectPart, textPart, htmlPart = may contain Tag Names for personalization
  1327  //  2. Tag Name = using {{tagName}} within the string defined above in #1
  1328  //  3. example:
  1329  //     a) Greetings, {{name}}
  1330  //     b) <h1>hello {{name}}, how are you</h1><p>Today is {{dayOfWeek}}</p>
  1331  //     c) <html><head></head><body><h1>hello {{name}}, how are you</h1><p>Today is {{dayOfWeek}}</p></body></html>
  1332  //  4. when sending template mail, the Tag Name values are replaced via key-Value pairs within TemplateData in SendTemplateEmail and SendBulkTemplateEmail methods:
  1333  //     a) { "name":"Harry", "dayOfWeek":"Monday" }
  1334  //
  1335  // notes:
  1336  //
  1337  //			a) Template = name of template to apply to the email
  1338  //			b) DefaultTemplateData = json string holding key-value pair of Tag Name and Tag Value (see below about template tokens)
  1339  //	  							 acting as a catch all default in case destination level replacement template data is not set
  1340  //			c) Source = email address of sender
  1341  //			d) ReturnPath = return email address (usually same as source)
  1342  //			e) ReplyToAddresses = list of email addresses for email reply to
  1343  //			f) Destinations = one or more Destinations, each defining target, and replacement template data for that specific destination
  1344  //			g) ConfigurationSetName = if ses has a set defined, and need to be used herein
  1345  //
  1346  // limits:
  1347  //  1. bulk is limited to 50 destinations per single call (subject to aws ses limits on account)
  1348  func (s *SES) SendBulkTemplateEmail(senderEmail string,
  1349  	returnPath string,
  1350  	replyTo string,
  1351  	templateName string,
  1352  	defaultTemplateDataJson string,
  1353  	emailTargetList []*EmailTarget,
  1354  	timeOutDuration ...time.Duration) (resultList []*BulkEmailMessageResult, failedCount int, err error) {
  1355  	segCtx := context.Background()
  1356  	segCtxSet := false
  1357  
  1358  	seg := xray.NewSegmentNullable("SES-SendBulkTemplateEmail", s._parentSegment)
  1359  
  1360  	if seg != nil {
  1361  		segCtx = seg.Ctx
  1362  		segCtxSet = true
  1363  
  1364  		defer seg.Close()
  1365  		defer func() {
  1366  			_ = seg.Seg.AddMetadata("SES-SendBulkTemplateEmail-Email-From", senderEmail)
  1367  			_ = seg.Seg.AddMetadata("SES-SendBulkTemplateEmail-ReturnPath", returnPath)
  1368  			_ = seg.Seg.AddMetadata("SES-SendBulkTemplateEmail-ReplyTo", replyTo)
  1369  			_ = seg.Seg.AddMetadata("SES-SendBulkTemplateEmail-TemplateName", templateName)
  1370  			_ = seg.Seg.AddMetadata("SES-SendBulkTemplateEmail-DefaultTemplateDataJson", defaultTemplateDataJson)
  1371  			_ = seg.Seg.AddMetadata("SES-SendBulkTemplateEmail-EmailTargetList-Count", len(emailTargetList))
  1372  			_ = seg.Seg.AddMetadata("SES-SendBulkTemplateEmail-Result-FailCount", failedCount)
  1373  
  1374  			if err != nil {
  1375  				_ = seg.Seg.AddError(err)
  1376  			}
  1377  		}()
  1378  	}
  1379  
  1380  	// validate
  1381  	if s.sesClient == nil {
  1382  		err = errors.New("SendBulkTemplateEmail Failed: " + "SES Client is Required")
  1383  		return nil, 0, err
  1384  	}
  1385  
  1386  	if util.LenTrim(senderEmail) <= 0 {
  1387  		err = errors.New("SendBulkTemplateEmail Failed: " + "Sender Email is Required")
  1388  		return nil, 0, err
  1389  	}
  1390  
  1391  	if util.LenTrim(templateName) <= 0 {
  1392  		err = errors.New("SendBulkTemplateEmail Failed: " + "Template Name is Required")
  1393  		return nil, 0, err
  1394  	}
  1395  
  1396  	if len(emailTargetList) <= 0 {
  1397  		err = errors.New("SendBulkTemplateEmail Failed: " + "Email Target List is Required")
  1398  		return nil, 0, err
  1399  	}
  1400  
  1401  	// create input object
  1402  	input := &ses.SendBulkTemplatedEmailInput{
  1403  		Template: aws.String(templateName),
  1404  		Source:   aws.String(senderEmail),
  1405  	}
  1406  
  1407  	if util.LenTrim(defaultTemplateDataJson) > 0 {
  1408  		input.DefaultTemplateData = aws.String(defaultTemplateDataJson)
  1409  	}
  1410  
  1411  	if util.LenTrim(returnPath) > 0 {
  1412  		input.ReturnPath = aws.String(returnPath)
  1413  	} else {
  1414  		input.ReturnPath = aws.String(senderEmail)
  1415  	}
  1416  
  1417  	if util.LenTrim(replyTo) > 0 {
  1418  		input.ReplyToAddresses = []*string{aws.String(replyTo)}
  1419  	} else {
  1420  		input.ReplyToAddresses = []*string{aws.String(senderEmail)}
  1421  	}
  1422  
  1423  	if input.Destinations == nil {
  1424  		for _, v := range emailTargetList {
  1425  			dest := new(ses.BulkEmailDestination)
  1426  
  1427  			if dest.Destination == nil {
  1428  				dest.Destination = new(ses.Destination)
  1429  			}
  1430  
  1431  			isSet := false
  1432  
  1433  			if len(v.To) > 0 {
  1434  				isSet = true
  1435  				dest.Destination.ToAddresses = aws.StringSlice(v.To)
  1436  			}
  1437  
  1438  			if len(v.CC) > 0 {
  1439  				isSet = true
  1440  				dest.Destination.CcAddresses = aws.StringSlice(v.CC)
  1441  			}
  1442  
  1443  			if len(v.BCC) > 0 {
  1444  				isSet = true
  1445  				dest.Destination.BccAddresses = aws.StringSlice(v.BCC)
  1446  			}
  1447  
  1448  			if util.LenTrim(v.TemplateDataJson) > 0 {
  1449  				dest.ReplacementTemplateData = aws.String(v.TemplateDataJson)
  1450  			}
  1451  
  1452  			if isSet {
  1453  				input.Destinations = append(input.Destinations, dest)
  1454  			}
  1455  		}
  1456  	}
  1457  
  1458  	if util.LenTrim(s.ConfigurationSetName) > 0 {
  1459  		input.ConfigurationSetName = aws.String(s.ConfigurationSetName)
  1460  	}
  1461  
  1462  	// perform action
  1463  	var output *ses.SendBulkTemplatedEmailOutput
  1464  
  1465  	if len(timeOutDuration) > 0 {
  1466  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1467  		defer cancel()
  1468  
  1469  		output, err = s.sesClient.SendBulkTemplatedEmailWithContext(ctx, input)
  1470  	} else {
  1471  		if segCtxSet {
  1472  			output, err = s.sesClient.SendBulkTemplatedEmailWithContext(segCtx, input)
  1473  		} else {
  1474  			output, err = s.sesClient.SendBulkTemplatedEmail(input)
  1475  		}
  1476  	}
  1477  
  1478  	// evaluate result
  1479  	if err != nil {
  1480  		err = errors.New("SendBulkTemplateEmail Failed: (Send Action) " + err.Error())
  1481  		return nil, 0, err
  1482  	}
  1483  
  1484  	for _, v := range output.Status {
  1485  		success := false
  1486  
  1487  		if strings.ToUpper(aws.StringValue(v.Status)) == "SUCCESS" {
  1488  			success = true
  1489  		} else {
  1490  			failedCount++
  1491  		}
  1492  
  1493  		resultList = append(resultList, &BulkEmailMessageResult{
  1494  			MessageId: aws.StringValue(v.MessageId),
  1495  			Status:    aws.StringValue(v.Status),
  1496  			ErrorInfo: aws.StringValue(v.Error),
  1497  			Success:   success,
  1498  		})
  1499  	}
  1500  
  1501  	return resultList, failedCount, nil
  1502  }
  1503  
  1504  // ----------------------------------------------------------------------------------------------------------------
  1505  // SES custom verification email methods
  1506  // ----------------------------------------------------------------------------------------------------------------
  1507  
  1508  // CreateCustomVerificationEmailTemplate will create a template for use with custom verification of email address
  1509  //
  1510  // parameters:
  1511  //  1. templateName = the name of the template, must be unique
  1512  //  2. templateSubject = the subject of the verification email (note that there is no tag name value replacement here)
  1513  //  3. templateContent = the body of the email, can be html or text (note that there is no tag name value replacement here)
  1514  //  4. fromEmailAddress = the email address that the verification email is sent from (must be email address)
  1515  //  5. successRedirectionURL = the url that users are sent to if their email addresses are successfully verified
  1516  //  6. failureRedirectionURL = the url that users are sent to if their email addresses are not successfully verified
  1517  //  7. timeOutDuration = optional time out value to use in context
  1518  func (s *SES) CreateCustomVerificationEmailTemplate(templateName string,
  1519  	templateSubject string,
  1520  	templateContent string,
  1521  	fromEmailAddress string,
  1522  	successRedirectionURL string,
  1523  	failureRedirectionURL string,
  1524  	timeOutDuration ...time.Duration) (err error) {
  1525  	segCtx := context.Background()
  1526  	segCtxSet := false
  1527  
  1528  	seg := xray.NewSegmentNullable("SES-CreateCustomVerificationEmailTemplate", s._parentSegment)
  1529  
  1530  	if seg != nil {
  1531  		segCtx = seg.Ctx
  1532  		segCtxSet = true
  1533  
  1534  		defer seg.Close()
  1535  		defer func() {
  1536  			_ = seg.Seg.AddMetadata("SES-CreateCustomVerificationEmailTemplate-TemplateName", templateName)
  1537  			_ = seg.Seg.AddMetadata("SES-CreateCustomVerificationEmailTemplate-TemplateSubject", templateSubject)
  1538  			_ = seg.Seg.AddMetadata("SES-CreateCustomVerificationEmailTemplate-TemplateContent", templateContent)
  1539  			_ = seg.Seg.AddMetadata("SES-CreateCustomVerificationEmailTemplate-Email-From", fromEmailAddress)
  1540  			_ = seg.Seg.AddMetadata("SES-CreateCustomVerificationEmailTemplate-Success-RedirectURL", successRedirectionURL)
  1541  			_ = seg.Seg.AddMetadata("SES-CreateCustomVerificationEmailTemplate-Failure-RedirectURL", failureRedirectionURL)
  1542  
  1543  			if err != nil {
  1544  				_ = seg.Seg.AddError(err)
  1545  			}
  1546  		}()
  1547  	}
  1548  
  1549  	// validate
  1550  	if s.sesClient == nil {
  1551  		err = errors.New("CreateCustomVerificationEmailTemplate Failed: " + "SES Client is Required")
  1552  		return err
  1553  	}
  1554  
  1555  	if util.LenTrim(templateName) <= 0 {
  1556  		err = errors.New("CreateCustomVerificationEmailTemplate Failed: " + "Template Name is Required")
  1557  		return err
  1558  	}
  1559  
  1560  	if util.LenTrim(templateSubject) <= 0 {
  1561  		err = errors.New("CreateCustomVerificationEmailTemplate Failed: " + "Template Subject is Required")
  1562  		return err
  1563  	}
  1564  
  1565  	if util.LenTrim(templateContent) <= 0 {
  1566  		err = errors.New("CreateCustomVerificationEmailTemplate Failed: " + "Template Content is Required")
  1567  		return err
  1568  	}
  1569  
  1570  	if util.LenTrim(fromEmailAddress) <= 0 {
  1571  		err = errors.New("CreateCustomVerificationEmailTemplate Failed: " + "From Email Address is Required")
  1572  		return err
  1573  	}
  1574  
  1575  	if util.LenTrim(successRedirectionURL) <= 0 {
  1576  		err = errors.New("CreateCustomVerificationEmailTemplate Failed: " + "Success Redirection URL is Required")
  1577  		return err
  1578  	}
  1579  
  1580  	if util.LenTrim(failureRedirectionURL) <= 0 {
  1581  		err = errors.New("CreateCustomVerificationEmailTemplate Failed: " + "Failure Redirection URL is Required")
  1582  		return err
  1583  	}
  1584  
  1585  	// create input object
  1586  	input := &ses.CreateCustomVerificationEmailTemplateInput{
  1587  		TemplateName:          aws.String(templateName),
  1588  		TemplateSubject:       aws.String(templateSubject),
  1589  		TemplateContent:       aws.String(templateContent),
  1590  		FromEmailAddress:      aws.String(fromEmailAddress),
  1591  		SuccessRedirectionURL: aws.String(successRedirectionURL),
  1592  		FailureRedirectionURL: aws.String(failureRedirectionURL),
  1593  	}
  1594  
  1595  	// perform action
  1596  	if len(timeOutDuration) > 0 {
  1597  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1598  		defer cancel()
  1599  
  1600  		_, err = s.sesClient.CreateCustomVerificationEmailTemplateWithContext(ctx, input)
  1601  	} else {
  1602  		if segCtxSet {
  1603  			_, err = s.sesClient.CreateCustomVerificationEmailTemplateWithContext(segCtx, input)
  1604  		} else {
  1605  			_, err = s.sesClient.CreateCustomVerificationEmailTemplate(input)
  1606  		}
  1607  	}
  1608  
  1609  	// evaluate result
  1610  	if err != nil {
  1611  		// error
  1612  		err = errors.New("CreateCustomVerificationEmailTemplate Failed: (Create Template Action) " + err.Error())
  1613  		return err
  1614  	} else {
  1615  		// success
  1616  		return nil
  1617  	}
  1618  }
  1619  
  1620  // UpdateCustomVerificationEmailTemplate will update a template for use with custom verification of email address
  1621  //
  1622  // parameters:
  1623  //  1. templateName = the name of the template, must be unique
  1624  //  2. templateSubject = the subject of the verification email (note that there is no tag name value replacement here)
  1625  //  3. templateContent = the body of the email, can be html or text (note that there is no tag name value replacement here)
  1626  //  4. fromEmailAddress = the email address that the verification email is sent from (must be email address)
  1627  //  5. successRedirectionURL = the url that users are sent to if their email addresses are successfully verified
  1628  //  6. failureRedirectionURL = the url that users are sent to if their email addresses are not successfully verified
  1629  //  7. timeOutDuration = optional time out value to use in context
  1630  func (s *SES) UpdateCustomVerificationEmailTemplate(templateName string,
  1631  	templateSubject string,
  1632  	templateContent string,
  1633  	fromEmailAddress string,
  1634  	successRedirectionURL string,
  1635  	failureRedirectionURL string,
  1636  	timeOutDuration ...time.Duration) (err error) {
  1637  	segCtx := context.Background()
  1638  	segCtxSet := false
  1639  
  1640  	seg := xray.NewSegmentNullable("SES-UpdateCustomVerificationEmailTemplate", s._parentSegment)
  1641  
  1642  	if seg != nil {
  1643  		segCtx = seg.Ctx
  1644  		segCtxSet = true
  1645  
  1646  		defer seg.Close()
  1647  		defer func() {
  1648  			_ = seg.Seg.AddMetadata("SES-UpdateCustomVerificationEmailTemplate-TemplateName", templateName)
  1649  			_ = seg.Seg.AddMetadata("SES-UpdateCustomVerificationEmailTemplate-TemplateSubject", templateSubject)
  1650  			_ = seg.Seg.AddMetadata("SES-UpdateCustomVerificationEmailTemplate-TemplateContent", templateContent)
  1651  			_ = seg.Seg.AddMetadata("SES-UpdateCustomVerificationEmailTemplate-Email-From", fromEmailAddress)
  1652  			_ = seg.Seg.AddMetadata("SES-UpdateCustomVerificationEmailTemplate-Success-RedirectURL", successRedirectionURL)
  1653  			_ = seg.Seg.AddMetadata("SES-UpdateCustomVerificationEmailTemplate-Failure-RedirectURL", failureRedirectionURL)
  1654  
  1655  			if err != nil {
  1656  				_ = seg.Seg.AddError(err)
  1657  			}
  1658  		}()
  1659  	}
  1660  
  1661  	// validate
  1662  	if s.sesClient == nil {
  1663  		err = errors.New("UpdateCustomVerificationEmailTemplate Failed: " + "SES Client is Required")
  1664  		return err
  1665  	}
  1666  
  1667  	if util.LenTrim(templateName) <= 0 {
  1668  		err = errors.New("UpdateCustomVerificationEmailTemplate Failed: " + "Template Name is Required")
  1669  		return err
  1670  	}
  1671  
  1672  	if util.LenTrim(templateSubject) <= 0 {
  1673  		err = errors.New("UpdateCustomVerificationEmailTemplate Failed: " + "Template Subject is Required")
  1674  		return err
  1675  	}
  1676  
  1677  	if util.LenTrim(templateContent) <= 0 {
  1678  		err = errors.New("UpdateCustomVerificationEmailTemplate Failed: " + "Template Content is Required")
  1679  		return err
  1680  	}
  1681  
  1682  	if util.LenTrim(fromEmailAddress) <= 0 {
  1683  		err = errors.New("UpdateCustomVerificationEmailTemplate Failed: " + "From Email Address is Required")
  1684  		return err
  1685  	}
  1686  
  1687  	if util.LenTrim(successRedirectionURL) <= 0 {
  1688  		err = errors.New("UpdateCustomVerificationEmailTemplate Failed: " + "Success Redirection URL is Required")
  1689  		return err
  1690  	}
  1691  
  1692  	if util.LenTrim(failureRedirectionURL) <= 0 {
  1693  		err = errors.New("UpdateCustomVerificationEmailTemplate Failed: " + "Failure Redirection URL is Required")
  1694  		return err
  1695  	}
  1696  
  1697  	// create input object
  1698  	input := &ses.UpdateCustomVerificationEmailTemplateInput{
  1699  		TemplateName:          aws.String(templateName),
  1700  		TemplateSubject:       aws.String(templateSubject),
  1701  		TemplateContent:       aws.String(templateContent),
  1702  		FromEmailAddress:      aws.String(fromEmailAddress),
  1703  		SuccessRedirectionURL: aws.String(successRedirectionURL),
  1704  		FailureRedirectionURL: aws.String(failureRedirectionURL),
  1705  	}
  1706  
  1707  	// perform action
  1708  	if len(timeOutDuration) > 0 {
  1709  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1710  		defer cancel()
  1711  
  1712  		_, err = s.sesClient.UpdateCustomVerificationEmailTemplateWithContext(ctx, input)
  1713  	} else {
  1714  		if segCtxSet {
  1715  			_, err = s.sesClient.UpdateCustomVerificationEmailTemplateWithContext(segCtx, input)
  1716  		} else {
  1717  			_, err = s.sesClient.UpdateCustomVerificationEmailTemplate(input)
  1718  		}
  1719  	}
  1720  
  1721  	// evaluate result
  1722  	if err != nil {
  1723  		// error
  1724  		err = errors.New("UpdateCustomVerificationEmailTemplate Failed: (Update Template Action) " + err.Error())
  1725  		return err
  1726  	} else {
  1727  		// success
  1728  		return nil
  1729  	}
  1730  }
  1731  
  1732  // DeleteCustomVerificationEmailTemplate will delete a custom verification email template
  1733  //
  1734  // parameters:
  1735  //  1. templateName = name of the template to delete
  1736  //  2. timeOutDuration = optional time out value to use in context
  1737  func (s *SES) DeleteCustomVerificationEmailTemplate(templateName string, timeOutDuration ...time.Duration) (err error) {
  1738  	segCtx := context.Background()
  1739  	segCtxSet := false
  1740  
  1741  	seg := xray.NewSegmentNullable("SES-DeleteCustomVerificationEmailTemplate", s._parentSegment)
  1742  
  1743  	if seg != nil {
  1744  		segCtx = seg.Ctx
  1745  		segCtxSet = true
  1746  
  1747  		defer seg.Close()
  1748  		defer func() {
  1749  			_ = seg.Seg.AddMetadata("SES-DeleteCustomVerificationEmailTemplate-TemplateName", templateName)
  1750  
  1751  			if err != nil {
  1752  				_ = seg.Seg.AddError(err)
  1753  			}
  1754  		}()
  1755  	}
  1756  
  1757  	// validate
  1758  	if s.sesClient == nil {
  1759  		err = errors.New("DeleteCustomVerificationEmailTemplate Failed: " + "SES Client is Required")
  1760  		return err
  1761  	}
  1762  
  1763  	if util.LenTrim(templateName) <= 0 {
  1764  		err = errors.New("DeleteCustomVerificationEmailTemplate Failed: " + "Template Name is Required")
  1765  		return err
  1766  	}
  1767  
  1768  	// create input object
  1769  	input := &ses.DeleteCustomVerificationEmailTemplateInput{
  1770  		TemplateName: aws.String(templateName),
  1771  	}
  1772  
  1773  	// perform action
  1774  	if len(timeOutDuration) > 0 {
  1775  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1776  		defer cancel()
  1777  
  1778  		_, err = s.sesClient.DeleteCustomVerificationEmailTemplateWithContext(ctx, input)
  1779  	} else {
  1780  		if segCtxSet {
  1781  			_, err = s.sesClient.DeleteCustomVerificationEmailTemplateWithContext(segCtx, input)
  1782  		} else {
  1783  			_, err = s.sesClient.DeleteCustomVerificationEmailTemplate(input)
  1784  		}
  1785  	}
  1786  
  1787  	// evaluate result
  1788  	if err != nil {
  1789  		err = errors.New("DeleteCustomVerificationEmailTemplate Failed: (Delete Template Action) " + err.Error())
  1790  		return err
  1791  	} else {
  1792  		return nil
  1793  	}
  1794  }
  1795  
  1796  // SendCustomVerificationEmail will send out a custom verification email to recipient
  1797  //
  1798  // parameters:
  1799  //  1. templateName = name of the template to use for the verification email
  1800  //  2. toEmailAddress = the email address to send verification to
  1801  //  3. timeOutDuration = optional time out value to use in context
  1802  func (s *SES) SendCustomVerificationEmail(templateName string, toEmailAddress string, timeOutDuration ...time.Duration) (messageId string, err error) {
  1803  	segCtx := context.Background()
  1804  	segCtxSet := false
  1805  
  1806  	seg := xray.NewSegmentNullable("SES-SendCustomVerificationEmail", s._parentSegment)
  1807  
  1808  	if seg != nil {
  1809  		segCtx = seg.Ctx
  1810  		segCtxSet = true
  1811  
  1812  		defer seg.Close()
  1813  		defer func() {
  1814  			_ = seg.Seg.AddMetadata("SES-SendCustomVerificationEmail-TemplateName", templateName)
  1815  			_ = seg.Seg.AddMetadata("SES-SendCustomVerificationEmail-Email-To", toEmailAddress)
  1816  			_ = seg.Seg.AddMetadata("SES-SendCustomVerificationEmail-Result-MessageID", messageId)
  1817  
  1818  			if err != nil {
  1819  				_ = seg.Seg.AddError(err)
  1820  			}
  1821  		}()
  1822  	}
  1823  
  1824  	// validate
  1825  	if s.sesClient == nil {
  1826  		err = errors.New("SendCustomVerificationEmail Failed: " + "SES Client is Required")
  1827  		return "", err
  1828  	}
  1829  
  1830  	if util.LenTrim(templateName) <= 0 {
  1831  		err = errors.New("SendCustomVerificationEmail Failed: " + "Template Name is Required")
  1832  		return "", err
  1833  	}
  1834  
  1835  	if util.LenTrim(toEmailAddress) <= 0 {
  1836  		err = errors.New("SendCustomVerificationEmail Failed: " + "To-Email Address is Required")
  1837  		return "", err
  1838  	}
  1839  
  1840  	// create input object
  1841  	input := &ses.SendCustomVerificationEmailInput{
  1842  		TemplateName: aws.String(templateName),
  1843  		EmailAddress: aws.String(toEmailAddress),
  1844  	}
  1845  
  1846  	if util.LenTrim(s.ConfigurationSetName) > 0 {
  1847  		input.ConfigurationSetName = aws.String(s.ConfigurationSetName)
  1848  	}
  1849  
  1850  	// perform action
  1851  	var output *ses.SendCustomVerificationEmailOutput
  1852  
  1853  	if len(timeOutDuration) > 0 {
  1854  		ctx, cancel := context.WithTimeout(segCtx, timeOutDuration[0])
  1855  		defer cancel()
  1856  
  1857  		output, err = s.sesClient.SendCustomVerificationEmailWithContext(ctx, input)
  1858  	} else {
  1859  		if segCtxSet {
  1860  			output, err = s.sesClient.SendCustomVerificationEmailWithContext(segCtx, input)
  1861  		} else {
  1862  			output, err = s.sesClient.SendCustomVerificationEmail(input)
  1863  		}
  1864  	}
  1865  
  1866  	// evaluate result
  1867  	if err != nil {
  1868  		// failure
  1869  		err = errors.New("SendCustomVerificationEmail Failed: (Send Action) " + err.Error())
  1870  		return "", err
  1871  	} else {
  1872  		// success
  1873  		messageId = *output.MessageId
  1874  		return messageId, nil
  1875  	}
  1876  }