Skip to content

Instantly share code, notes, and snippets.

@etowett
Created June 29, 2020 08:16
Show Gist options
  • Save etowett/9699e8479889d3aecfb87bf24a52d8a8 to your computer and use it in GitHub Desktop.
Save etowett/9699e8479889d3aecfb87bf24a52d8a8 to your computer and use it in GitHub Desktop.
Lambda function to get email from SES and extract attachment to s3
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"log"
"os"
"path"
"time"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/ses"
enmime "github.com/cention-sany/go.enmime"
"github.com/cention-sany/net/mail"
)
var (
sesClient *ses.SES
s3Client *s3.S3
)
func main() {
s3Region := os.Getenv("AWS_REGION")
sess, err := session.NewSession()
if err != nil {
log.Fatalf("AWS NewSession failed: %s", err)
}
sesClient = ses.New(sess)
s3Client = s3.New(sess, aws.NewConfig().WithRegion(s3Region))
lambda.Start(handler)
}
func handler(event events.SimpleEmailEvent) error {
for _, sesMail := range event.Records {
jsonMail, err := json.Marshal(sesMail)
if err != nil {
log.Printf("failed to json marshal event: %v", err)
}
log.Printf("sesMail: %v", string(jsonMail))
if err := processMail(&sesMail); err != nil {
return err
}
}
return nil
}
func processMail(original *events.SimpleEmailRecord) error {
s3Mail, err := getFromS3(original)
if err != nil {
return err
}
defer s3Mail.Close()
// parse the original message
parsedMail, err := mail.ReadMessage(s3Mail)
if err != nil {
return fmt.Errorf("ReadMessage failed: %s", err)
}
mime, err := enmime.ParseMIMEBody(parsedMail)
if err != nil {
return fmt.Errorf("ParseMIMEBody failed: %s", err)
}
log.Printf("From: %v", parsedMail.Header.Get("From"))
log.Printf("Subject: %v", parsedMail.Header.Get("Subject"))
log.Printf("To: %v", parsedMail.Header.Get("To"))
log.Printf("Text Body: %v\n", mime.Text)
log.Printf("HTML Body: %v\n", mime.HTML)
log.Printf("Inlines: %v\n", mime.Inlines)
for _, attach := range mime.Attachments {
attachmentFile := fmt.Sprintf("%v-%v", time.Now().UnixNano(), attach.FileName())
log.Printf("Uploading : %v to s3\n", attachmentFile)
_, err := s3Client.PutObject(&s3.PutObjectInput{
Bucket: aws.String(os.Getenv("S3_BUCKET")),
Key: aws.String(attachmentFile),
ACL: aws.String("private"),
Body: bytes.NewReader(attach.Content()),
ContentType: aws.String(attach.ContentType()),
ContentDisposition: aws.String(attach.Disposition()),
ServerSideEncryption: aws.String("AES256"),
StorageClass: aws.String("INTELLIGENT_TIERING"),
})
if err != nil {
log.Printf("upload to s3 failed: %v\n", err)
}
}
return nil
}
func getFromS3(original *events.SimpleEmailRecord) (io.ReadCloser, error) {
key := path.Join(os.Getenv("S3_PREFIX"), original.SES.Mail.MessageID)
obj, err := s3Client.GetObject(&s3.GetObjectInput{
Bucket: aws.String(os.Getenv("S3_BUCKET")),
Key: aws.String(key),
})
if err != nil {
return nil, fmt.Errorf("S3 GetObject failed: %s", err)
}
return obj.Body, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment