Skip to content

Commit

Permalink
Add ses email support (#640)
Browse files Browse the repository at this point in the history
* add support for SES email integration

* add support for SES email integration

* add support for SES email integration

* add support for SES email integration - add missing credentials providing for aws

* add support for SES email integration - conditional sourceArn

* add support for SES email integration - conditional sourceArn

* add support for SES email integration - add assume role option. fix error handling.

* error handling

* error handling

* error handling

* increase session duration to 900 (minimum value)

* fix logging

* email - SES - create session with the credentials only if they were passed. otherwise we assume the credentials from credentials assume chain
  • Loading branch information
yosiz-aqua authored May 29, 2024
1 parent 6893264 commit 4c102ce
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 0 deletions.
2 changes: 2 additions & 0 deletions data/integrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type OutputSettings struct {
Headers map[string][]string `json:"headers,omitempty"`
Template string `json:"template,omitempty"`
Language string `json:"language,omitempty"`
UseAwsSes bool `json:"use-aws-ses,omitempty"`
AwsSesConfig map[string]string `json:"aws-ses-config,omitempty"`
}

type OutputResponse struct {
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ require (
require (
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/aws/aws-sdk-go v1.51.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.43.16/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.51.4 h1:yOVfGhRJyReBrACK0alLosJl8iXhWkNY1vrePYmhHdw=
github.com/aws/aws-sdk-go v1.51.4/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
Expand Down Expand Up @@ -602,6 +604,7 @@ github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6t
github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
Expand Down
119 changes: 119 additions & 0 deletions outputs/email.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import (
"crypto/tls"
"errors"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ses"
"github.com/aws/aws-sdk-go/service/sts"
"net"
"strconv"
"strings"
Expand Down Expand Up @@ -35,6 +40,8 @@ type EmailOutput struct {
ClientHostName string
UseMX bool
sendFunc func(addr string, a customsmtp.Auth, from string, to []string, msg []byte) error
UseAwsSes bool
AwsSesConfig map[string]string
}

func (email *EmailOutput) GetType() string {
Expand Down Expand Up @@ -142,6 +149,10 @@ func (email *EmailOutput) Send(content map[string]string) (data.OutputResponse,
return data.OutputResponse{}, errThereIsNoRecipient
}

if email.UseAwsSes {
return email.sendViaAwsSesService(email.AwsSesConfig, subject, body, recipients)
}

msg := fmt.Sprintf(
"To: %s\r\n"+
"From: %s\r\n"+
Expand Down Expand Up @@ -194,3 +205,111 @@ func (email EmailOutput) sendViaMxServers(port string, msg string, recipients []
}
}
}

func (email *EmailOutput) sendViaAwsSesService(awsConfig map[string]string,
subject, body string, recipients []string) (data.OutputResponse, error) {
log.Logger.Debugf("Sending to email via %q using SES", email.Name)

// Create a new AWS session
sess, err := getAwsSession(awsConfig)
if err != nil {
log.Logger.Errorf("Error sending email - %s", err)
return data.OutputResponse{}, err
}

// Create a new SES service client
svc := ses.New(sess)

emailInput := &ses.SendEmailInput{
Destination: &ses.Destination{
ToAddresses: prepareToEmailAddressList(recipients),
},
Message: &ses.Message{
Body: &ses.Body{
Html: &ses.Content{
Data: aws.String(body),
},
},
Subject: &ses.Content{
Data: aws.String(subject),
},
},
Source: aws.String(awsConfig["fromEmailAddress"]),
}

sourceArnConfig := awsConfig["arn"]
if sourceArnConfig != "" {
emailInput.SourceArn = aws.String(sourceArnConfig)
}

// Send the email
output, err := svc.SendEmail(emailInput)
if err != nil {
log.Logger.Errorf("Error sending email - %s", err)
return data.OutputResponse{}, err
} else {
log.Logger.Debugf("The message was sent successfully via aws-ses aws-messageId:%s", *output.MessageId)
return data.OutputResponse{Key: *output.MessageId}, err
}

}

func prepareToEmailAddressList(recipients []string) []*string {
// Convert to array of string pointers
toAddresses := make([]*string, len(recipients))
for i, str := range recipients {
toAddresses[i] = aws.String(str)
}

return toAddresses
}

func getAwsSession(awsConfig map[string]string) (*session.Session, error) {
// Create a new AWS session
awsRegion := awsConfig["awsRegion"]

config := &aws.Config{
Region: aws.String(awsRegion),
}
if awsConfig["id"] != "" {
log.Logger.Debugf("Using credentials from awsConfig")
config.Credentials = credentials.NewStaticCredentials(awsConfig["id"], awsConfig["secretAccessKey"], awsConfig["awsSessionToken"])
}

sess, err := session.NewSession(config)
if err != nil {
log.Logger.Errorf("Failed sending email - failed to create session with AWS for given credentials %s", err)
return nil, err
}

roleToAssume := awsConfig["assumeRole"]
if roleToAssume != "" {
stsSvc := sts.New(sess)

result, err := stsSvc.AssumeRole(&sts.AssumeRoleInput{
RoleArn: aws.String(roleToAssume),
RoleSessionName: aws.String("SendEmailSession"), // TODO : add some identification if needed for customer_id?.
DurationSeconds: aws.Int64(900),
})

if err != nil {
log.Logger.Errorf("Failed sending email - Failed assuming role: %s", err)
return nil, err
}

tempCreds := result.Credentials
tempSession, err := session.NewSession(&aws.Config{
Credentials: credentials.NewStaticCredentials(*tempCreds.AccessKeyId, *tempCreds.SecretAccessKey, *tempCreds.SessionToken),
Region: aws.String(awsRegion),
})

if err != nil {
log.Logger.Errorf("Failed sending email - Failed creating session for assumed role: %s", err)
return nil, err
}

return tempSession, nil
}

return sess, nil
}
2 changes: 2 additions & 0 deletions router/builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ func buildEmailOutput(sourceSettings *data.OutputSettings) *outputs.EmailOutput
Recipients: sourceSettings.Recipients,
ClientHostName: sourceSettings.ClientHostName,
UseMX: sourceSettings.UseMX,
UseAwsSes: sourceSettings.UseAwsSes,
AwsSesConfig: sourceSettings.AwsSesConfig,
}
}

Expand Down

0 comments on commit 4c102ce

Please sign in to comment.