Skip to content

Commit

Permalink
Merge pull request #60 from FloRul/feature/email-attachments
Browse files Browse the repository at this point in the history
Added the option to add attachments when sending an email response.
  • Loading branch information
FloRul authored Mar 15, 2024
2 parents 7583d5f + eb1323a commit 539672c
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 35 deletions.
Original file line number Diff line number Diff line change
@@ -1,27 +1,49 @@
{
"Records": [
{
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
"receiptHandle": "MessageReceiptHandle",
"body": "Quel est le nombre maximum de jours pour prendre des vacances ?",
"messageId": "9997254c-560c-4e3d-a8bf-442318bf5bf9",
"receiptHandle": "AQEBfui1DK9NTuG5jV+6m/275yYhWfGYS+8UoGEi3M+HLS1BSKGw6YZWCEHb8k9VT4DEg3COU3lCagt+9mgang1/STRoKUEvyFt6ciSYesX2I7VHn75RUY+f0XgHc/7F+p124U3ugTHzmhQASIR1Er0C2lczfoSMhIeVqqtgdFGXjzBGJ6ZTP5YdcOhHWOBeL2LjQcCypTew3T2TE/qSsBO451nLigjPGGgg13sJDGha1uxSy2ILXKrtNBF/ugPn3DZq3c8PFqpCtNzyn2seQzC97bLVWC6J6Tt2zF7/GmZ9IYP5FTik1XU7QDJYksDh35r2G0czubhyP5g1fkrP6YhqGQ==",
"eventSourceARN": "arn:aws:sqs:us-east-1:446872271111:levio-demo-fev-email-response-processor-queue-dev.fifo",
"eventSource": "aws:sqs",
"awsRegion": "us-east-1",
"body": "Resume response",
"md5OfBody": "f3dcab2186d689158fcb2b758759c5f6",
"md5OfMessageAttributes": "3484a7928d62feab81a7f3d085ce9fe2",
"attributes": {
"sender": "[email protected]",
"subject": "Levio HR"
"ApproximateReceiveCount": "1",
"SentTimestamp": "1710275621941",
"SequenceNumber": "18884574632926447616",
"MessageGroupId": "[email protected]",
"SenderId": "AROAWQC5JXED6GYDWVIPM:ResumeRequestProcessor-ResumeRequestProcessorFunct-y6fYGqtNKouH",
"MessageDeduplicationId": "fegu2ar9ktaph6b1o66k8t2eaiqgff1f4s2pfa81",
"ApproximateFirstReceiveTimestamp": "1710275621941"
},
"messageAttributes": {
"sender": {
"stringValue": "[email protected]",
"stringListValues": [],
"binaryListValues": [],
"dataType": "String"
},
"subject": {
"stringValue": "Levio HR",
"stringValue": "Test Resume 2",
"stringListValues": [],
"binaryListValues": [],
"dataType": "String"
},
"attachment1": {
"stringValue": "s3://levio-demo-fev-esta-ses-bucket-dev/resume/AudioTestResume2-fegu2ar9ktaph6b1o66k8t2eaiqgff1f4s2pfa81.txt",
"stringListValues": [],
"binaryListValues": [],
"dataType": "String"
},
"attachment0": {
"stringValue": "s3://levio-demo-fev-esta-ses-bucket-dev/resume/dialogue/AudioTestResume2-fegu2ar9ktaph6b1o66k8t2eaiqgff1f4s2pfa81.txt",
"stringListValues": [],
"binaryListValues": [],
"dataType": "String"
}
},
"md5OfBody": "{{{md5_of_body}}}",
"eventSource": "aws:sqs",
"eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:MyQueue",
"awsRegion": "us-east-1"
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,27 @@ module "lambda_function_container_image" {
ses = {
effect = "Allow"
actions = [
"ses:SendEmail"
"ses:SendEmail",
"ses:SendRawEmail"
]
resources = [
"arn:aws:ses:${var.aws_region}:${data.aws_caller_identity.current.account_id}:*"
]
}

s3 = {
effect = "Allow"
actions = [
"s3:Get*",
"s3:List*",
"s3:Describe*",
"s3-object-lambda:Get*",
"s3-object-lambda:List*"
]
resources = [
"arn:aws:s3:*:*:*"
]
}
}

create_current_version_allowed_triggers = false
Expand Down
15 changes: 15 additions & 0 deletions lambdas/EmailProcessor/EmailResponseProcessorFunction/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,26 @@
<artifactId>sesv2</artifactId>
<version>2.20.109</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<version>2.20.52</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>apache-client</artifactId>
<version>2.20.27</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>jakarta.mail</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>jakarta.mail</groupId>
<artifactId>jakarta.mail-api</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import com.levio.awsdemo.emailresponseprocessor.service.EmailService;
import com.levio.awsdemo.emailresponseprocessor.service.S3Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class App implements RequestHandler<SQSEvent, Void> {

private final EmailService emailService;

public App() {
this.emailService = new EmailService();
this.emailService = new EmailService(new S3Service());
}

public App(EmailService emailService) {
Expand All @@ -28,9 +30,16 @@ public Void handleRequest(SQSEvent event, Context context) {
SQSEvent.MessageAttribute sender = record.getMessageAttributes().get("sender");
SQSEvent.MessageAttribute subject = record.getMessageAttributes().get("subject");

List<String> attachments = new ArrayList<>();
record.getMessageAttributes().forEach((key, value) -> {
if (key.startsWith("attachment")) {
attachments.add(value.getStringValue());
}
});

if (!message.isEmpty() && sender != null && subject != null) {
try {
emailService.send(message, sender.getStringValue(), subject.getStringValue());
emailService.send(message, sender.getStringValue(), subject.getStringValue(), attachments);
} catch (Exception e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
package com.levio.awsdemo.emailresponseprocessor.service;

import jakarta.activation.DataHandler;
import jakarta.activation.DataSource;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.Session;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeBodyPart;
import jakarta.mail.internet.MimeMessage;
import jakarta.mail.internet.MimeMultipart;
import jakarta.mail.util.ByteArrayDataSource;
import lombok.RequiredArgsConstructor;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sesv2.SesV2Client;
import software.amazon.awssdk.services.sesv2.model.Body;
import software.amazon.awssdk.services.sesv2.model.Content;
import software.amazon.awssdk.services.sesv2.model.Destination;
import software.amazon.awssdk.services.sesv2.model.EmailContent;
import software.amazon.awssdk.services.sesv2.model.Message;
import software.amazon.awssdk.services.sesv2.model.RawMessage;
import software.amazon.awssdk.services.sesv2.model.SendEmailRequest;
import software.amazon.awssdk.services.sesv2.model.SesV2Exception;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Properties;

@RequiredArgsConstructor
public class EmailService {

private static final String SENDER_EMAIL = System.getenv("SENDER_EMAIL");
Expand All @@ -19,30 +36,60 @@ public class EmailService {
.region(Region.US_EAST_1)
.build();

public void send(String message, String recipient, String subject) {
Content content = Content.builder()
.data(message)
.build();
private final S3Service s3Service;

Destination destination = Destination.builder()
.toAddresses(recipient)
.build();
public void send(String message, String recipient, String subject, List<String> attachments) throws MessagingException, IOException {
Session session = Session.getDefaultInstance(new Properties());

Content sub = Content.builder()
.data(subject)
.build();
MimeMessage mimeMessage = new MimeMessage(session);

mimeMessage.setSubject(subject, "UTF-8");
mimeMessage.setFrom(new InternetAddress(SENDER_EMAIL));
mimeMessage.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipient));

MimeMultipart messageBody = new MimeMultipart("alternative");

MimeBodyPart wrap = new MimeBodyPart();

MimeBodyPart bodyPart = new MimeBodyPart();
bodyPart.setContent(message, "text/html; charset=UTF-8");

messageBody.addBodyPart(bodyPart);

wrap.setContent(messageBody);

MimeMultipart mimeMultipart = new MimeMultipart("mixed");

Body body = Body.builder()
.html(content)
mimeMultipart.addBodyPart(wrap);

for (String attachment : attachments) {
MimeBodyPart att = new MimeBodyPart();

InputStream inputStream = s3Service.getFile(attachment);
byte[] byteArray = inputStream.readAllBytes();

DataSource dataSource = new ByteArrayDataSource(byteArray, "application/octet-stream");
att.setDataHandler(new DataHandler(dataSource));
att.setFileName(extractFilename(attachment));

mimeMultipart.addBodyPart(att);
}

mimeMessage.setContent(mimeMultipart);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
mimeMessage.writeTo(outputStream);

RawMessage rawMsg = RawMessage.builder()
.data(SdkBytes.fromByteBuffer(ByteBuffer.wrap(outputStream.toByteArray())))
.build();

Message msg = Message.builder()
.subject(sub)
.body(body)
Destination destination = Destination.builder()
.toAddresses(recipient)
.build();

EmailContent emailContent = EmailContent.builder()
.simple(msg)
.raw(rawMsg)
.build();

SendEmailRequest emailRequest = SendEmailRequest.builder()
Expand All @@ -60,4 +107,9 @@ public void send(String message, String recipient, String subject) {
throw e;
}
}
}

private String extractFilename(String attachment) {
String[] parts = attachment.split("/");
return parts[parts.length - 1];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.levio.awsdemo.emailresponseprocessor.service;

import software.amazon.awssdk.core.ResponseBytes;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;

import java.io.InputStream;

public class S3Service {

private final S3Client s3 = S3Client.builder()
.region(Region.US_EAST_1)
.build();

public InputStream getFile(String uri) {
GetObjectRequest objectRequest = GetObjectRequest
.builder()
.key(extractKey(uri))
.bucket(extractBucket(uri))
.build();

ResponseBytes<GetObjectResponse> objectBytes = s3.getObjectAsBytes(objectRequest);
return objectBytes.asInputStream();
}

private String extractBucket(String uri) {
int endIndex = uri.indexOf("/", 5);
return uri.substring(5, endIndex);
}

private String extractKey(String uri) {
int startIndex = uri.indexOf("/", 5);
return uri.substring(startIndex + 1);
}

}

0 comments on commit 539672c

Please sign in to comment.