0
0
Lập trình
Flame Kris
Flame Krisbacodekiller

Cấu hình AWS SES gửi email về Gmail bằng Terraform

Đăng vào 1 tuần trước

• 9 phút đọc

Giới thiệu

Trong thời đại công nghệ hiện nay, việc quản lý email một cách hiệu quả là vô cùng quan trọng, đặc biệt là đối với các doanh nghiệp và nhà phát triển. Nếu bạn sở hữu một miền riêng và muốn tạo một địa chỉ email tùy chỉnh mà không cần phải tự quản lý máy chủ email, AWS Simple Email Service (SES) là một giải pháp lý tưởng. Bài viết này sẽ hướng dẫn bạn cách cấu hình AWS SES để gửi email tới Gmail qua Terraform.

Kiến trúc tổng thể

AWS SES cho phép bạn gửi và nhận email mà không cần quản lý máy chủ. Dưới đây là sơ đồ tổng quan về cách thức hoạt động của hệ thống này:

  1. Một tin nhắn được gửi tới địa chỉ email tùy chỉnh của bạn.
  2. Dịch vụ DNS (AWS Route 53) sẽ có một bản ghi MX trỏ tới SES.
  3. AWS SES sẽ lưu email này vào một bucket S3.
  4. Bucket S3 sẽ kích hoạt một hàm Lambda để đọc tin nhắn và chuyển tiếp nó tới địa chỉ Gmail của bạn.
  5. Khi bạn nhận được email trong hộp thư Gmail, bạn có thể trả lời từ địa chỉ email tùy chỉnh của mình.

Triển khai cấu hình

Vì chúng ta đang sử dụng AWS, việc áp dụng phương pháp Infrastructure as Code (IAC) với Terraform là hợp lý. Dưới đây là hướng dẫn từng bước để cấu hình các thành phần trong giải pháp này.

Cấu hình Terraform

Trước tiên, hãy chắc chắn rằng bạn đã thiết lập một bucket S3 để lưu trữ trạng thái Terraform:

hcl Copy
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
  backend "s3" {
    bucket = "<điền tên bucket của bạn vào đây>"
    key    = "ses-gmail-custom-domain/terraform.tfstate"
    region = "us-east-1"
  }
}

Tiếp theo, hãy tạo một danh tính SES và cấu hình DKIM:

hcl Copy
## Danh tính miền SES
resource "aws_ses_domain_identity" "identity" {
  domain = var.domain_name
}

## Cấu hình DKIM cho danh tính miền SES
resource "aws_ses_domain_dkim" "dkim" {
  domain = aws_ses_domain_identity.identity.domain
}

Sau khi hoàn tất, hãy xác minh quyền sở hữu miền và thiết lập các bản ghi MX, DKIM, SPF và DMARC trong Route 53:

hcl Copy
## Xác minh quyền sở hữu miền SES -> miền tùy chỉnh
resource "aws_route53_record" "amazonses_identity_verification_record" {
  zone_id = data.aws_route53_zone.hosted_zone.id
  name    = "_amazonses.${var.domain_name}"
  type    = "TXT"
  ttl     = "600"
  records = [aws_ses_domain_identity.identity.verification_token]
}

## Bản ghi DKIM cho danh tính miền SES
resource "aws_route53_record" "amazonses_identity_dkim_records" {
  for_each = toset(aws_ses_domain_dkim.dkim.dkim_tokens)
  zone_id = data.aws_route53_zone.hosted_zone.id
  name    = "${each.key}._domainkey.${aws_ses_domain_identity.identity.domain}"
  type    = "CNAME"
  ttl     = 600
  records = ["${each.key}.dkim.amazonses.com"]
}

## Bản ghi MX trỏ tới máy chủ SES
resource "aws_route53_record" "mx_record" {
  zone_id = data.aws_route53_zone.hosted_zone.id
  name    = data.aws_route53_zone.hosted_zone.name
  type    = "MX"
  ttl     = 600
  records = ["10 inbound-smtp.${var.region}.amazonaws.com"]
}

## Bản ghi SPF cho phép amazonses.com gửi email thay mặt cho miền của bạn
resource "aws_route53_record" "spf_record" {
  zone_id = data.aws_route53_zone.hosted_zone.id
  name    = data.aws_route53_zone.hosted_zone.name
  type    = "TXT"
  ttl     = 600
  records = ["v=spf1 include:amazonses.com -all"]
}

## Bản ghi DMARC
resource "aws_route53_record" "dmarc_record" {
  zone_id = data.aws_route53_zone.hosted_zone.id
  name    = "_dmarc.${data.aws_route53_zone.hosted_zone.name}"
  type    = "TXT"
  ttl     = 600
  records = ["v=DMARC1; p=none;"]
}

Tạo Bucket S3 để lưu email

Tiếp theo, chúng ta sẽ tạo một bucket S3 để lưu trữ các email gửi tới miền tùy chỉnh của chúng ta và kích hoạt hàm Lambda:

hcl Copy
## Bucket S3 cho email đến
resource "aws_s3_bucket" "incoming_email_bucket" {
  bucket = "ses-inbox-${var.author}"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "encryption" {
  bucket = aws_s3_bucket.incoming_email_bucket.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

resource "aws_s3_bucket_notification" "bucket_notification" {
  bucket = aws_s3_bucket.incoming_email_bucket.id

  lambda_function {
    lambda_function_arn = aws_lambda_function.lambda_forwarder.arn
    events              = ["s3:ObjectCreated:*"]
  }

  depends_on = [aws_lambda_permission.s3_bucket_event]
}

Khi có email mới trong bucket, hàm Lambda sẽ được kích hoạt để lấy tin nhắn từ bucket và gửi tới tài khoản Gmail của chúng ta thông qua SES (đừng quên về quyền hạn):

hcl Copy
## Hàm Lambda chuyển tiếp email
data "archive_file" "lambda_zip" {
  output_path = "lambda.zip"
  type        = "zip"
  source_dir  = "lambda-forwarder-source-code"
}

resource "aws_iam_role" "lambda_role" {
  name_prefix        = "ses-email-forwarder-role"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "lambda_policy" {
  name_prefix = "ses-email-forwarder-role-policy"
  policy = jsonencode(
    {
      Version : "2012-10-17",
      Statement : [
        {
          "Effect" : "Allow",
          "Action" : [
            "logs:CreateLogGroup",
            "logs:CreateLogStream",
            "logs:PutLogEvents",
            "logs:DescribeLogStreams"
            ], Resource : [
            "*"
          ]
        },
        {
          "Effect" : "Allow",
          "Action" : [
            "s3:GetObject"
          ],
          "Resource" : [
            "${aws_s3_bucket.incoming_email_bucket.arn}/*"
          ]
        },
        {
          "Effect" : "Allow",
          "Action" : [
            "ses:SendEmail",
            "ses:SendRawEmail"
          ],
          "Resource" : "*"
        }
      ]
  })
  role = aws_iam_role.lambda_role.id
}

resource "aws_lambda_function" "lambda_forwarder" {
  filename         = "lambda.zip"
  function_name    = "ses-email-forwarder"
  role             = aws_iam_role.lambda_role.arn
  handler          = "lambda.lambda_handler"
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
  runtime          = "python3.9"
  environment {
    variables = {
      REGION     = var.region
      FORWARD_TO = var.original_email
      DOMAIN     = var.domain_name
    }
  }
}

resource "aws_lambda_permission" "s3_bucket_event" {
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.lambda_forwarder.arn
  principal     = "s3.amazonaws.com"
  statement_id  = "event_permissions_from_${aws_s3_bucket.incoming_email_bucket.bucket}"
  source_arn    = aws_s3_bucket.incoming_email_bucket.arn
}

Kết quả và cấu hình Gmail

Sau khi áp dụng cấu hình Terraform, đầu ra sẽ chứa các tham số cần thiết cho việc thiết lập phần Gmail:

hcl Copy
output "ses_smtp_server" {
  value = "email-smtp.${var.region}.amazonaws.com" ## kiểm tra trong cài đặt SES -> SMTP
}

output "ses_smtp_server_port" {
  value = "587"
}

## Thông tin xác thực người dùng SMTP sẽ được sử dụng bên phía Gmail để gửi email thay mặt cho SES
output "ses_smtp_user_username" {
  value = nonsensitive(aws_iam_access_key.ses_smtp_access_key.id) # chỉ để thử nghiệm, không nên sử dụng trong môi trường sản xuất
}

output "ses_smtp_user_password" {
  value = nonsensitive(aws_iam_access_key.ses_smtp_access_key.ses_smtp_password_v4) # chỉ để thử nghiệm, không nên sử dụng trong môi trường sản xuất
}

Sử dụng các thông tin này, bạn có thể vào cài đặt tài khoản Gmail và tạo một bí danh với tên miền tùy chỉnh mới.

Lưu ý quan trọng về chế độ Sandbox của SES

Để có thể gửi và trả lời mọi địa chỉ email, bạn cần thoát khỏi chế độ sandbox trong SES. Để làm điều này, hãy gửi yêu cầu tới hỗ trợ AWS với nội dung như sau:

Tôi đã thiết lập một miền tùy chỉnh trong SES liên kết với tài khoản gmail.com của tôi. Khi ai đó gửi email tới địa chỉ email tùy chỉnh của tôi, nó sẽ đến tài khoản gmail.com của tôi. Tuy nhiên, tôi không thể trả lời cho người nhận từ đó, vì trong chế độ sandbox, tôi phải xác minh email của người nhận trước. Để tránh giới hạn này, tôi muốn thoát khỏi chế độ sandbox và có thể trả lời bất kỳ ai liên hệ với tôi qua email tùy chỉnh của tôi.

Khi được phê duyệt, bạn sẽ thấy một thông báo xác nhận.

Tổng kết

Việc cấu hình AWS SES để gửi email tới Gmail qua Terraform không chỉ giúp tiết kiệm thời gian mà còn mang lại sự linh hoạt trong quản lý email. Đừng quên kiểm tra và đảm bảo mọi quyền hạn cần thiết đã được thiết lập đúng cách. Nếu bạn cần thêm thông tin hoặc hướng dẫn, hãy tham khảo tài liệu chính thức của AWS và Terraform.

Hỏi đáp (FAQ)

1. Tôi có cần xác minh email người nhận khi sử dụng SES không?
Có, trong chế độ sandbox, bạn cần xác minh từng địa chỉ email người nhận. Khi bạn thoát khỏi chế độ sandbox, bạn có thể gửi email tới bất kỳ địa chỉ nào.

2. Có cách nào khác để gửi email từ miền tùy chỉnh không?
Ngoài SES, bạn cũng có thể sử dụng các dịch vụ khác như SendGrid, Mailgun, nhưng SES thường là lựa chọn tiết kiệm chi phí và hiệu quả.

3. Lambda có phải là lựa chọn tốt cho việc xử lý email không?
Có, AWS Lambda giúp bạn xử lý email một cách dễ dàng và hiệu quả mà không cần quản lý máy chủ.

4. Có nên sử dụng mã nguồn mở cho chức năng chuyển tiếp email không?
Có, bạn có thể tìm thấy nhiều dự án mã nguồn mở trên GitHub để tham khảo và tùy chỉnh theo nhu cầu của mình.

5. Tôi có thể sử dụng AWS SES ở đâu?
AWS SES có sẵn tại nhiều vùng, bạn chỉ cần chọn vùng mà bạn muốn triển khai dịch vụ này.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào