AWS

AWS E-mail Forwarding

또또니엘 2024. 7. 15. 17:13

✏️   글 작성 이유

- 본 글은 서비스 운영에 있어서 사용하고있는 서비스의 도메인 주소와 동일한 도메인의 이메일을 사용하여 클라이언트와 소통 하기 위해 이루어진 작업을 공유하고자 한다.

ex) 도메인 주소 - smiletap.kr, 사용하고자 하는 메일 admin@smiletap.kr 

 

🔎   채택한 방식

- 이메일 포워딩 방식은 아래 3가지 단계를 거쳐 구축하였다.

 

1️⃣  AWS SES(Simple Email Service) 서비스로 허가된 도메인 또는 메일주소의 메일을 수신
2️⃣  이메일 수신과 함께 AWS SNS(Simple Notification Service) 주제에 게시, S3(Simple Storage Service) 버킷에 전송(백업용)
3️⃣  SNS서비스에 이메일 수신이 게시된 후 해당 SNS서비스를 구독하고 있던 Lambda가 지정된 메일로 수신한 메일을 전송

 

🔨  구현 설명

- AWS SES(Simple Email Service) 서비스로 허가된 도메인 또는 메일주소의 메일을 수신

 

1️⃣  Rout53에서 해당 도메인 호스팅 영역에 아래와 같이 레코드를 추가

 


✳️  MX 레코드 :  DNS 레코드의 일종으로 도메인의 메일 교환 서버를 저장합니다. 이메일을 올바른 위치로 라우팅하는 데 사용됩니다.

 

✳️  10 inbound-smtp.us-east-1.amazonaws.com : 앞 숫자 10은 우선순위를 나타내며 뒤 inbound 부터 끝까지는 메일 서버의 도메인 이름을 나타낸다. 즉, 10 inbound-smtp.us-east-1.amazonaws.com이라는 MX 레코드는 메일이 해당 도메인으로 전송될 때 inbound-smtp.us-east-1.amazonaws.com 서버로 전달되며, 이 서버가 다른 MX 레코드보다 더 높은 우선순위를 가진다는 것을 의미한다.

 

 

 

 

 

2️⃣  SES서비스 내에 이메일 수신 세팅

- 이메일 수신 클릭

- 규칙 세트 생성 클릭 - 규칙 세트 이름 기입 후 규칙 세트 생성

 

 

 

- 규칙 생성  클릭 -> 규칙 이름을 정하고 아래와같이 세팅 후 다음

 

 

 

- 지침에 따라 수신자를 추가한 후 다음 버튼 클릭
- 새작업 추가를 통해 
1. SNS 주제에 게시 추가 후, SNS 주제 선택( * SNS가 없다면 SNS 주제 생성을 통해 SNS 생성)
2. S3 버킷으로 전송 추가, S3 버킷 선택( * S3 버킷이 없다면 S3버킷 생성을 통해 S3 생성)

- 모두 추가한 후 다음 -> 큐칙 생성
- 생성된 큐칙 세트와 큐칙을 확인 -> 모두 활성 상태로 만들어준다.

* 만약 SNS 주제와 S3버킷을 새로 생성했다면 각각 서비스의 대시보드를 확인하면 새로 만들어진 주제와 버킷을 확인 할 수 있다.

 

 

3️⃣  SNS서비스에 이메일 수신이 게시된 후 해당 SNS서비스를 구독하고 있던 Lambda가 지정된 메일로 수신한 메일을 전송

 

- 이메일 전송을 위한 lambda 생성
- lambda서비스에 접속 후 함수 생성 클릭( 다양한 런타임을 선택할 수 있지만 본인은 Node가 편하기에 Node를 선택했다)
- 생성된 함수 내에서 트리거 추가 클릭
- 아래와 같이 트리거를 SNS로 선택 후 위에서 선택 또는 생성한 SNS 주제를 넣어준 후 추가 

 

 

 

 

 

 

 

 

 

- 마지막으로 아래 이미지에 나타난 부분에 이메일 전송 코드를 구현하면 완료된다
* 트리거가 발동되면 event객체로 트리거 내용이 전달된다. 해당 객체를 분석해서 본문을 추출한 후 이메일 전송 코드에 넣어줄 수 있다.



* Node 이메일 전송 코드 ( 아래 코드는 본인 사용한 Node 메일 전송 코드이지만 아직 부족하여 리팩토링이 많이 필요해보인다.)

import { SendEmailCommand } from "@aws-sdk/client-ses";
import { SESClient } from "@aws-sdk/client-ses";

const REGION = "us-east-1";
const sesClient = new SESClient({ region: REGION });

export const handler = async (event) => {
    try {
        const records = event.Records;
        
        if (!records || records.length === 0) {
            console.log('No records found.');
            return { statusCode: 200, body: 'No records found.' };
        }
    
        const snsMessage = JSON.parse(records[0].Sns.Message);
        const email = snsMessage.mail;

        const senderName = 'TESTNAME'; 
        const senderEmail = test@test.kr';
        const recipients = ['test@testkr']; 
        
        const mailMeta = Buffer.from(snsMessage.content, 'base64').toString('utf-8');
        const mailMetaArr = mailMeta.split("------Boundary-WM")
        const contentMeta = mailMetaArr[mailMetaArr.length -2].split("base64")
        const contentBase64 = contentMeta[1].trim()
        const content = Buffer.from(contentBase64, 'base64').toString('utf-8');
        
        const sendEmailParams = {
            Source: `${senderName} <${senderEmail}>`,  
            Destination: { ToAddresses: recipients },
            Message: {
                Subject: { Data: email.commonHeaders.subject || '' },
                Body: {
                    Html: {
                      Charset: "UTF-8",
                      Data: content || ''
                    },
                }
            }
        };
    
        const sendEmailCommand = new SendEmailCommand(sendEmailParams);

        const data = await sesClient.send(sendEmailCommand);
        
        console.log("Email sent:", data);
        return { statusCode: 200, body: 'Email sent successfully.' };
        
    } catch (error) {
        console.error("Failed to send email.", error);
        
        const sendErrorEmailParams = {
            Source: "test@test.kr", 
            Destination: { ToAddresses: ['test@test.kr'] },
            Message: {
                Subject: { Data: 'SES_MAIL_FORWARDER ERROR' },
                Body: {
                     Text: {
                      Charset: "UTF-8",
                      Data: error,
                    },
                }
            }
        };
        
        const sendErrorEmailCommand = new SendEmailCommand(sendErrorEmailParams);
    
        await sesClient.send(sendErrorEmailCommand);
        return { statusCode: 500, body: 'Failed to send email.' };
    }
};