github.com/argoproj/argo-events@v1.9.1/sensors/triggers/email/email.go (about) 1 /* 2 Copyright 2020 BlackRock, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 package email 17 18 import ( 19 "context" 20 "encoding/json" 21 "errors" 22 "fmt" 23 "regexp" 24 25 notifications "github.com/argoproj/notifications-engine/pkg/services" 26 "go.uber.org/zap" 27 28 "github.com/argoproj/argo-events/common" 29 "github.com/argoproj/argo-events/common/logging" 30 apicommon "github.com/argoproj/argo-events/pkg/apis/common" 31 "github.com/argoproj/argo-events/pkg/apis/sensor/v1alpha1" 32 "github.com/argoproj/argo-events/sensors/triggers" 33 ) 34 35 type EmailTrigger struct { 36 // Sensor refer to the sensor object 37 Sensor *v1alpha1.Sensor 38 // Trigger refers to the trigger resource 39 Trigger *v1alpha1.Trigger 40 // Logger to log stuff 41 Logger *zap.SugaredLogger 42 // emailSvc refers to the Email notification service. 43 emailSvc notifications.NotificationService 44 } 45 46 // NewEmailTrigger returns a new Email trigger context 47 func NewEmailTrigger(sensor *v1alpha1.Sensor, trigger *v1alpha1.Trigger, logger *zap.SugaredLogger) (*EmailTrigger, error) { 48 emailTrigger := trigger.Template.Email 49 var smtpPassword string 50 if emailTrigger.SMTPPassword != nil { 51 var err error 52 smtpPassword, err = common.GetSecretFromVolume(emailTrigger.SMTPPassword) 53 if err != nil { 54 return nil, fmt.Errorf("failed to retrieve the smtp password, %w", err) 55 } 56 } 57 emailSvc := notifications.NewEmailService( 58 notifications.EmailOptions{ 59 Host: emailTrigger.Host, 60 Port: int(emailTrigger.Port), 61 Username: emailTrigger.Username, 62 Password: smtpPassword, 63 From: emailTrigger.From, 64 }, 65 ) 66 return &EmailTrigger{ 67 Sensor: sensor, 68 Trigger: trigger, 69 Logger: logger.With(logging.LabelTriggerType, apicommon.EmailTrigger), 70 emailSvc: emailSvc, 71 }, nil 72 } 73 74 // GetTriggerType returns the type of the trigger 75 func (t *EmailTrigger) GetTriggerType() apicommon.TriggerType { 76 return apicommon.EmailTrigger 77 } 78 79 func (t *EmailTrigger) FetchResource(ctx context.Context) (interface{}, error) { 80 return t.Trigger.Template.Email, nil 81 } 82 83 func (t *EmailTrigger) ApplyResourceParameters(events map[string]*v1alpha1.Event, resource interface{}) (interface{}, error) { 84 resourceBytes, err := json.Marshal(resource) 85 if err != nil { 86 return nil, fmt.Errorf("failed to marshal the Email trigger resource, %w", err) 87 } 88 parameters := t.Trigger.Template.Email.Parameters 89 90 if parameters != nil { 91 updatedResourceBytes, err := triggers.ApplyParams(resourceBytes, t.Trigger.Template.Email.Parameters, events) 92 if err != nil { 93 return nil, err 94 } 95 96 var st *v1alpha1.EmailTrigger 97 if err := json.Unmarshal(updatedResourceBytes, &st); err != nil { 98 return nil, fmt.Errorf("failed to unmarshal the updated Email trigger resource after applying resource parameters, %w", err) 99 } 100 101 return st, nil 102 } 103 104 return resource, nil 105 } 106 107 // Execute executes the trigger 108 func (t *EmailTrigger) Execute(ctx context.Context, events map[string]*v1alpha1.Event, resource interface{}) (interface{}, error) { 109 t.Logger.Info("executing EmailTrigger") 110 _, ok := resource.(*v1alpha1.EmailTrigger) 111 if !ok { 112 return nil, fmt.Errorf("failed to marshal the Email trigger resource") 113 } 114 115 emailTrigger := t.Trigger.Template.Email 116 117 if len(emailTrigger.To) == 0 { 118 return nil, fmt.Errorf("to can't be empty") 119 } 120 body := emailTrigger.Body 121 if body == "" { 122 return nil, fmt.Errorf("body can't be empty") 123 } 124 subject := emailTrigger.Subject 125 if subject == "" { 126 return nil, fmt.Errorf("subject can't be empty") 127 } 128 t.Logger.Infow("sending emails...", zap.Any("to", emailTrigger.To)) 129 var errs error 130 validEmail := regexp.MustCompile(`^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$`) 131 for _, addr := range emailTrigger.To { 132 if !validEmail.MatchString(addr) { 133 t.Logger.Error("invalid emailId", zap.Any("to", addr)) 134 errs = errors.Join(errs, fmt.Errorf("to emailId can't be invalid %v", addr)) 135 continue 136 } 137 notification := notifications.Notification{ 138 Message: emailTrigger.Body, 139 Email: ¬ifications.EmailNotification{ 140 Subject: emailTrigger.Subject, 141 Body: emailTrigger.Body, 142 }, 143 } 144 destination := notifications.Destination{ 145 Service: "email", 146 Recipient: addr, 147 } 148 err := t.emailSvc.Send(notification, destination) 149 if err != nil { 150 t.Logger.Errorw("unable to send emails to emailId", zap.Any("to", addr), zap.Error(err)) 151 errs = errors.Join(errs, fmt.Errorf("failed to send emails to emailId %v, %w", addr, err)) 152 } 153 } 154 if errs != nil { 155 return nil, errs 156 } 157 t.Logger.Infow("message successfully sent to emailIds", zap.Any("message", emailTrigger.Body), zap.Any("to", emailTrigger.To)) 158 t.Logger.Info("finished executing EmailTrigger") 159 return nil, nil 160 } 161 162 // No Policies for EmailTrigger 163 func (t *EmailTrigger) ApplyPolicy(ctx context.Context, resource interface{}) error { 164 return nil 165 }