Skip to content

#238 Send an email on expense approval and denial - #326

Merged
mehanana merged 4 commits into
mainfrom
238-send-email-on-Expense-Approval-and-denial
Aug 26, 2026
Merged

#238 Send an email on expense approval and denial#326
mehanana merged 4 commits into
mainfrom
238-send-email-on-Expense-Approval-and-denial

Conversation

@mehanana

Copy link
Copy Markdown
Contributor

ℹ️ Issue

Closes #238

📝 Description

Used SES to send an email when an expense is approved/denied.

Briefly list the changes made to the code:

  1. Added the email functionality to PATCH endpoint where expense gets approved/denied
  2. Created mailer.ts with functions thata support the mail functionality
  3. Added SES email identity, IAM policy, and Env var to infrastructure/aws/lambda.tf to verify & send the email
  4. Wrote tests for the new functionality

✔️ Verification

What steps did you take to verify your changes work? These should be clear enough for someone to be able to clone the branch and follow the steps themselves.

Provide screenshots of any new components, styling changes, or pages.
Screenshot 2026-08-18 231623

🏕️ (Optional) Future Work / Notes

Did you notice anything ugly during the course of this ticket? Any bugs, design challenges, or unexpected behavior? Write it down so we can clean it up in a future ticket!

  • Just wanted to double check if the email address here was correct
  • If the expense is given the status needs_more_info, should this also trigger an email?

github-actions Bot added a commit that referenced this pull request Aug 19, 2026

@nshoreibah-kvyo nshoreibah-kvyo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mind testing this after you deploy? Thanks!

@nourshoreibah nourshoreibah left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above

mehanana and others added 2 commits August 26, 2026 00:38
wrote tests for the new functionality
  - Auto-formatted .tf files with terraform fmt
  - Updated README.md with terraform-docs

  Co-authored-by: mehanana <mehanana@users.noreply.github.com>
@mehanana
mehanana force-pushed the 238-send-email-on-Expense-Approval-and-denial branch from 587c9a5 to 88cd61a Compare August 26, 2026 04:49
github-actions Bot and others added 2 commits August 26, 2026 04:49
  - Auto-formatted .tf files with terraform fmt
  - Updated README.md with terraform-docs

  Co-authored-by: mehanana <mehanana@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Terraform Plan 📖 infrastructure/aws

Terraform Initialization ⚙️success

Terraform Validation 🤖success

Terraform Plan 📖success

Show Plan
data.archive_file.lambda_placeholder: Reading...
data.archive_file.lambda_placeholder: Read complete after 0s [id=96878a51e358033297a32b882fd5223cc95fb8a7]
data.aws_vpc.default: Reading...
aws_cloudfront_origin_access_control.frontend: Refreshing state... [id=E2T090T8V5CDLN]
aws_iam_openid_connect_provider.github: Refreshing state... [id=arn:aws:iam::489881683177:oidc-provider/token.actions.githubusercontent.com]
aws_api_gateway_rest_api.branch_api: Refreshing state... [id=2apxzxb0r8]
aws_iam_role.lambda_role: Refreshing state... [id=branch-lambda-role]
data.aws_caller_identity.current: Reading...
aws_cognito_user_pool.branch_user_pool: Refreshing state... [id=us-east-2_CxTueqe6g]
aws_s3_bucket.reports_bucket: Refreshing state... [id=c4c-branch-generated-reports20251030194253425700000001]
data.aws_caller_identity.current: Read complete after 0s [id=489881683177]
aws_cloudfront_function.rewrite_index: Refreshing state... [id=branch-frontend-rewrite-index]
aws_s3_bucket.lambda_deployments: Refreshing state... [id=branch-lambda-deployments-489881683177]
aws_s3_bucket.frontend: Refreshing state... [id=branch-frontend-489881683177]
data.aws_iam_policy_document.ci_preview_assume: Reading...
data.aws_iam_policy_document.ci_apply_assume: Reading...
data.aws_iam_policy_document.ci_apply_assume: Read complete after 0s [id=813913]
data.aws_iam_policy_document.ci_preview_assume: Read complete after 0s [id=282080688]
data.aws_iam_policy_document.ci_plan_assume: Reading...
data.aws_iam_policy_document.ci_migrate_assume: Reading...
data.aws_iam_policy_document.ci_migrate_assume: Read complete after 0s [id=3474878989]
data.aws_iam_policy_document.ci_plan_assume: Read complete after 0s [id=3057813384]
data.infisical_secrets.rds_folder: Reading...
data.infisical_secrets.sentry_folder: Reading...
data.infisical_secrets.sentry_folder: Read complete after 0s
data.infisical_secrets.grafana_folder: Reading...
data.infisical_secrets.rds_folder: Read complete after 0s
aws_iam_role.ci_apply: Refreshing state... [id=branch-ci-apply]
data.infisical_secrets.grafana_folder: Read complete after 0s
aws_iam_role.ci_preview: Refreshing state... [id=branch-ci-preview]
aws_iam_role.ci_migrate: Refreshing state... [id=branch-ci-migrate]
aws_iam_role.ci_plan: Refreshing state... [id=branch-ci-plan]
aws_iam_role_policy_attachment.lambda_basic: Refreshing state... [id=branch-lambda-role/arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole]
aws_api_gateway_gateway_response.cors["DEFAULT_4XX"]: Refreshing state... [id=aggr-2apxzxb0r8-DEFAULT_4XX]
aws_api_gateway_gateway_response.cors["DEFAULT_5XX"]: Refreshing state... [id=aggr-2apxzxb0r8-DEFAULT_5XX]
aws_api_gateway_resource.lambda_resources["users"]: Refreshing state... [id=0dkbds]
aws_api_gateway_resource.lambda_resources["donors"]: Refreshing state... [id=hybur2]
aws_api_gateway_resource.lambda_resources["expenditures"]: Refreshing state... [id=6sdj3w]
aws_api_gateway_resource.lambda_resources["reports"]: Refreshing state... [id=wsnfk2]
aws_api_gateway_resource.lambda_resources["auth"]: Refreshing state... [id=u8unad]
aws_api_gateway_resource.lambda_resources["projects"]: Refreshing state... [id=chhy2i]
aws_iam_role_policy_attachment.ci_apply_admin: Refreshing state... [id=branch-ci-apply/arn:aws:iam::aws:policy/AdministratorAccess]
aws_iam_role_policy.ci_preview: Refreshing state... [id=branch-ci-preview:preview-env]
aws_iam_role_policy.ci_plan_state_lock: Refreshing state... [id=branch-ci-plan:tfstate-lock]
aws_iam_role_policy_attachment.ci_plan_readonly: Refreshing state... [id=branch-ci-plan/arn:aws:iam::aws:policy/ReadOnlyAccess]
aws_cognito_user_pool_client.branch_client: Refreshing state... [id=570i6ocj0882qu0ditm4vrr60f]
aws_iam_role_policy.lambda_cognito_admin: Refreshing state... [id=branch-lambda-role:branch-lambda-cognito-admin]
aws_s3_bucket_server_side_encryption_configuration.lambda_deployments: Refreshing state... [id=branch-lambda-deployments-489881683177]
aws_s3_bucket_versioning.lambda_deployments: Refreshing state... [id=branch-lambda-deployments-489881683177]
aws_s3_object.lambda_placeholder["auth"]: Refreshing state... [id=branch-lambda-deployments-489881683177/auth/initial.zip]
aws_s3_object.lambda_placeholder["donors"]: Refreshing state... [id=branch-lambda-deployments-489881683177/donors/initial.zip]
aws_s3_object.lambda_placeholder["expenditures"]: Refreshing state... [id=branch-lambda-deployments-489881683177/expenditures/initial.zip]
aws_s3_object.lambda_placeholder["projects"]: Refreshing state... [id=branch-lambda-deployments-489881683177/projects/initial.zip]
aws_s3_object.lambda_placeholder["reports"]: Refreshing state... [id=branch-lambda-deployments-489881683177/reports/initial.zip]
aws_s3_object.lambda_placeholder["users"]: Refreshing state... [id=branch-lambda-deployments-489881683177/users/initial.zip]
data.aws_vpc.default: Read complete after 0s [id=vpc-0a9ccfb59c8918ce9]
aws_iam_role_policy.lambda_s3_objects: Refreshing state... [id=branch-lambda-role:branch-lambda-s3-objects]
aws_s3_bucket_public_access_block.reports_bucket_public_access: Refreshing state... [id=c4c-branch-generated-reports20251030194253425700000001]
aws_s3_bucket_public_access_block.frontend: Refreshing state... [id=branch-frontend-489881683177]
aws_api_gateway_resource.lambda_proxy["auth"]: Refreshing state... [id=srhf9j]
aws_api_gateway_resource.lambda_proxy["projects"]: Refreshing state... [id=kmwcxq]
aws_api_gateway_resource.lambda_proxy["donors"]: Refreshing state... [id=xkazax]
aws_api_gateway_resource.lambda_proxy["reports"]: Refreshing state... [id=elsvn3]
aws_api_gateway_resource.lambda_proxy["expenditures"]: Refreshing state... [id=14khv0]
aws_api_gateway_resource.lambda_proxy["users"]: Refreshing state... [id=4sjlu3]
aws_api_gateway_method.lambda_methods["auth-POST"]: Refreshing state... [id=agm-2apxzxb0r8-u8unad-POST]
aws_api_gateway_method.lambda_methods["expenditures-POST"]: Refreshing state... [id=agm-2apxzxb0r8-6sdj3w-POST]
aws_api_gateway_method.lambda_methods["projects-GET"]: Refreshing state... [id=agm-2apxzxb0r8-chhy2i-GET]
aws_api_gateway_method.lambda_methods["auth-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-u8unad-OPTIONS]
aws_api_gateway_method.lambda_methods["projects-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-chhy2i-OPTIONS]
aws_api_gateway_method.lambda_methods["donors-POST"]: Refreshing state... [id=agm-2apxzxb0r8-hybur2-POST]
aws_api_gateway_method.lambda_methods["users-POST"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-POST]
aws_api_gateway_method.lambda_methods["users-PATCH"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-PATCH]
aws_api_gateway_method.lambda_methods["reports-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-wsnfk2-OPTIONS]
aws_api_gateway_method.lambda_methods["users-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-OPTIONS]
aws_api_gateway_method.lambda_methods["projects-POST"]: Refreshing state... [id=agm-2apxzxb0r8-chhy2i-POST]
aws_api_gateway_method.lambda_methods["expenditures-PATCH"]: Refreshing state... [id=agm-2apxzxb0r8-6sdj3w-PATCH]
aws_api_gateway_method.lambda_methods["users-GET"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-GET]
aws_api_gateway_method.lambda_methods["users-DELETE"]: Refreshing state... [id=agm-2apxzxb0r8-0dkbds-DELETE]
aws_api_gateway_method.lambda_methods["donors-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-hybur2-OPTIONS]
aws_api_gateway_method.lambda_methods["auth-GET"]: Refreshing state... [id=agm-2apxzxb0r8-u8unad-GET]
aws_api_gateway_method.lambda_methods["expenditures-OPTIONS"]: Refreshing state... [id=agm-2apxzxb0r8-6sdj3w-OPTIONS]
aws_api_gateway_method.lambda_methods["reports-GET"]: Refreshing state... [id=agm-2apxzxb0r8-wsnfk2-GET]
aws_api_gateway_method.lambda_methods["donors-GET"]: Refreshing state... [id=agm-2apxzxb0r8-hybur2-GET]
aws_api_gateway_method.lambda_methods["expenditures-GET"]: Refreshing state... [id=agm-2apxzxb0r8-6sdj3w-GET]
aws_security_group.rds: Refreshing state... [id=sg-0c8a1ff1676a14edb]
aws_api_gateway_method.lambda_proxy_any["expenditures"]: Refreshing state... [id=agm-2apxzxb0r8-14khv0-ANY]
aws_api_gateway_method.lambda_proxy_any["projects"]: Refreshing state... [id=agm-2apxzxb0r8-kmwcxq-ANY]
aws_api_gateway_method.lambda_proxy_any["users"]: Refreshing state... [id=agm-2apxzxb0r8-4sjlu3-ANY]
aws_api_gateway_method.lambda_proxy_any["reports"]: Refreshing state... [id=agm-2apxzxb0r8-elsvn3-ANY]
aws_api_gateway_method.lambda_proxy_any["auth"]: Refreshing state... [id=agm-2apxzxb0r8-srhf9j-ANY]
aws_api_gateway_method.lambda_proxy_any["donors"]: Refreshing state... [id=agm-2apxzxb0r8-xkazax-ANY]
aws_api_gateway_method.cors_proxy_options["auth"]: Refreshing state... [id=agm-2apxzxb0r8-srhf9j-OPTIONS]
aws_api_gateway_method.cors_proxy_options["donors"]: Refreshing state... [id=agm-2apxzxb0r8-xkazax-OPTIONS]
aws_api_gateway_method.cors_proxy_options["expenditures"]: Refreshing state... [id=agm-2apxzxb0r8-14khv0-OPTIONS]
aws_api_gateway_method.cors_proxy_options["projects"]: Refreshing state... [id=agm-2apxzxb0r8-kmwcxq-OPTIONS]
aws_api_gateway_method.cors_proxy_options["reports"]: Refreshing state... [id=agm-2apxzxb0r8-elsvn3-OPTIONS]
aws_api_gateway_method.cors_proxy_options["users"]: Refreshing state... [id=agm-2apxzxb0r8-4sjlu3-OPTIONS]
aws_vpc_security_group_ingress_rule.rds_postgres: Refreshing state... [id=sgr-0594341dc6234d55c]
aws_vpc_security_group_egress_rule.rds_all: Refreshing state... [id=sgr-099fe0d98d4b3f3b5]
aws_cloudfront_distribution.frontend: Refreshing state... [id=E37FDHRYNZNF4R]
aws_db_instance.branch_rds: Refreshing state... [id=db-AMMYFTORW6XJGRELV7WQZCNHQI]
aws_api_gateway_method_response.cors["projects-proxy"]: Refreshing state... [id=agmr-2apxzxb0r8-kmwcxq-OPTIONS-200]
aws_api_gateway_method_response.cors["projects"]: Refreshing state... [id=agmr-2apxzxb0r8-chhy2i-OPTIONS-200]
aws_api_gateway_method_response.cors["reports-proxy"]: Refreshing state... [id=agmr-2apxzxb0r8-elsvn3-OPTIONS-200]
aws_api_gateway_method_response.cors["donors"]: Refreshing state... [id=agmr-2apxzxb0r8-hybur2-OPTIONS-200]
aws_api_gateway_method_response.cors["auth"]: Refreshing state... [id=agmr-2apxzxb0r8-u8unad-OPTIONS-200]
aws_api_gateway_method_response.cors["users"]: Refreshing state... [id=agmr-2apxzxb0r8-0dkbds-OPTIONS-200]
aws_api_gateway_method_response.cors["donors-proxy"]: Refreshing state... [id=agmr-2apxzxb0r8-xkazax-OPTIONS-200]
aws_api_gateway_method_response.cors["reports"]: Refreshing state... [id=agmr-2apxzxb0r8-wsnfk2-OPTIONS-200]
aws_api_gateway_method_response.cors["users-proxy"]: Refreshing state... [id=agmr-2apxzxb0r8-4sjlu3-OPTIONS-200]
aws_api_gateway_method_response.cors["expenditures"]: Refreshing state... [id=agmr-2apxzxb0r8-6sdj3w-OPTIONS-200]
aws_api_gateway_method_response.cors["expenditures-proxy"]: Refreshing state... [id=agmr-2apxzxb0r8-14khv0-OPTIONS-200]
aws_api_gateway_method_response.cors["auth-proxy"]: Refreshing state... [id=agmr-2apxzxb0r8-srhf9j-OPTIONS-200]
aws_api_gateway_integration.cors["donors"]: Refreshing state... [id=agi-2apxzxb0r8-hybur2-OPTIONS]
aws_api_gateway_integration.cors["reports-proxy"]: Refreshing state... [id=agi-2apxzxb0r8-elsvn3-OPTIONS]
aws_api_gateway_integration.cors["auth"]: Refreshing state... [id=agi-2apxzxb0r8-u8unad-OPTIONS]
aws_api_gateway_integration.cors["donors-proxy"]: Refreshing state... [id=agi-2apxzxb0r8-xkazax-OPTIONS]
aws_api_gateway_integration.cors["reports"]: Refreshing state... [id=agi-2apxzxb0r8-wsnfk2-OPTIONS]
aws_api_gateway_integration.cors["expenditures"]: Refreshing state... [id=agi-2apxzxb0r8-6sdj3w-OPTIONS]
aws_api_gateway_integration.cors["users-proxy"]: Refreshing state... [id=agi-2apxzxb0r8-4sjlu3-OPTIONS]
aws_api_gateway_integration.cors["expenditures-proxy"]: Refreshing state... [id=agi-2apxzxb0r8-14khv0-OPTIONS]
aws_api_gateway_integration.cors["projects"]: Refreshing state... [id=agi-2apxzxb0r8-chhy2i-OPTIONS]
aws_api_gateway_integration.cors["auth-proxy"]: Refreshing state... [id=agi-2apxzxb0r8-srhf9j-OPTIONS]
aws_api_gateway_integration.cors["users"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-OPTIONS]
aws_api_gateway_integration.cors["projects-proxy"]: Refreshing state... [id=agi-2apxzxb0r8-kmwcxq-OPTIONS]
data.aws_iam_policy_document.frontend_bucket: Reading...
data.aws_iam_policy_document.frontend_bucket: Read complete after 0s [id=1471335443]
aws_s3_bucket_policy.frontend: Refreshing state... [id=branch-frontend-489881683177]
aws_api_gateway_integration_response.cors["auth-proxy"]: Refreshing state... [id=agir-2apxzxb0r8-srhf9j-OPTIONS-200]
aws_api_gateway_integration_response.cors["donors-proxy"]: Refreshing state... [id=agir-2apxzxb0r8-xkazax-OPTIONS-200]
aws_api_gateway_integration_response.cors["reports"]: Refreshing state... [id=agir-2apxzxb0r8-wsnfk2-OPTIONS-200]
aws_api_gateway_integration_response.cors["auth"]: Refreshing state... [id=agir-2apxzxb0r8-u8unad-OPTIONS-200]
aws_api_gateway_integration_response.cors["users-proxy"]: Refreshing state... [id=agir-2apxzxb0r8-4sjlu3-OPTIONS-200]
aws_api_gateway_integration_response.cors["donors"]: Refreshing state... [id=agir-2apxzxb0r8-hybur2-OPTIONS-200]
aws_api_gateway_integration_response.cors["expenditures"]: Refreshing state... [id=agir-2apxzxb0r8-6sdj3w-OPTIONS-200]
aws_api_gateway_integration_response.cors["users"]: Refreshing state... [id=agir-2apxzxb0r8-0dkbds-OPTIONS-200]
aws_api_gateway_integration_response.cors["expenditures-proxy"]: Refreshing state... [id=agir-2apxzxb0r8-14khv0-OPTIONS-200]
aws_api_gateway_integration_response.cors["projects-proxy"]: Refreshing state... [id=agir-2apxzxb0r8-kmwcxq-OPTIONS-200]
aws_api_gateway_integration_response.cors["projects"]: Refreshing state... [id=agir-2apxzxb0r8-chhy2i-OPTIONS-200]
aws_api_gateway_integration_response.cors["reports-proxy"]: Refreshing state... [id=agir-2apxzxb0r8-elsvn3-OPTIONS-200]
aws_lambda_function.functions["donors"]: Refreshing state... [id=branch-donors]
aws_lambda_function.functions["expenditures"]: Refreshing state... [id=branch-expenditures]
aws_lambda_function.functions["projects"]: Refreshing state... [id=branch-projects]
aws_lambda_function.functions["reports"]: Refreshing state... [id=branch-reports]
aws_lambda_function.functions["users"]: Refreshing state... [id=branch-users]
aws_lambda_function.functions["auth"]: Refreshing state... [id=branch-auth]
aws_iam_role_policy.ci_migrate: Refreshing state... [id=branch-ci-migrate:db-migrate]
aws_lambda_permission.api_gateway_permissions["auth"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_api_gateway_integration.lambda_proxy_integrations["projects"]: Refreshing state... [id=agi-2apxzxb0r8-kmwcxq-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["reports"]: Refreshing state... [id=agi-2apxzxb0r8-elsvn3-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["expenditures"]: Refreshing state... [id=agi-2apxzxb0r8-14khv0-ANY]
aws_lambda_permission.api_gateway_permissions["donors"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_api_gateway_integration.lambda_proxy_integrations["auth"]: Refreshing state... [id=agi-2apxzxb0r8-srhf9j-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["donors"]: Refreshing state... [id=agi-2apxzxb0r8-xkazax-ANY]
aws_api_gateway_integration.lambda_proxy_integrations["users"]: Refreshing state... [id=agi-2apxzxb0r8-4sjlu3-ANY]
aws_lambda_permission.api_gateway_permissions["expenditures"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_lambda_permission.api_gateway_permissions["projects"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_lambda_permission.api_gateway_permissions["reports"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_lambda_permission.api_gateway_permissions["users"]: Refreshing state... [id=AllowAPIGatewayInvoke]
aws_api_gateway_integration.lambda_integrations["users-PATCH"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-PATCH]
aws_api_gateway_integration.lambda_integrations["projects-POST"]: Refreshing state... [id=agi-2apxzxb0r8-chhy2i-POST]
aws_api_gateway_integration.lambda_integrations["auth-POST"]: Refreshing state... [id=agi-2apxzxb0r8-u8unad-POST]
aws_api_gateway_integration.lambda_integrations["projects-GET"]: Refreshing state... [id=agi-2apxzxb0r8-chhy2i-GET]
aws_api_gateway_integration.lambda_integrations["donors-GET"]: Refreshing state... [id=agi-2apxzxb0r8-hybur2-GET]
aws_api_gateway_integration.lambda_integrations["expenditures-POST"]: Refreshing state... [id=agi-2apxzxb0r8-6sdj3w-POST]
aws_api_gateway_integration.lambda_integrations["expenditures-PATCH"]: Refreshing state... [id=agi-2apxzxb0r8-6sdj3w-PATCH]
aws_api_gateway_integration.lambda_integrations["users-POST"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-POST]
aws_api_gateway_integration.lambda_integrations["donors-POST"]: Refreshing state... [id=agi-2apxzxb0r8-hybur2-POST]
aws_api_gateway_integration.lambda_integrations["users-GET"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-GET]
aws_api_gateway_integration.lambda_integrations["users-DELETE"]: Refreshing state... [id=agi-2apxzxb0r8-0dkbds-DELETE]
aws_api_gateway_integration.lambda_integrations["auth-GET"]: Refreshing state... [id=agi-2apxzxb0r8-u8unad-GET]
aws_api_gateway_integration.lambda_integrations["expenditures-GET"]: Refreshing state... [id=agi-2apxzxb0r8-6sdj3w-GET]
aws_api_gateway_integration.lambda_integrations["reports-GET"]: Refreshing state... [id=agi-2apxzxb0r8-wsnfk2-GET]
aws_api_gateway_deployment.branch_deployment: Refreshing state... [id=tf9rqv]
aws_api_gateway_stage.branch_stage: Refreshing state... [id=ags-2apxzxb0r8-prod]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_iam_role_policy.lambda_ses_send will be created
  + resource "aws_iam_role_policy" "lambda_ses_send" {
      + id          = (known after apply)
      + name        = "branch-lambda-ses-send"
      + name_prefix = (known after apply)
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "ses:SendEmail",
                          + "ses:SendRawEmail",
                        ]
                      + Effect   = "Allow"
                      + Resource = "*"
                      + Sid      = "LambdaSesSendEmail"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + role        = "branch-lambda-role"
    }

Plan: 1 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

Pushed by: @mehanana, Action: pull_request

@mehanana
mehanana added this pull request to the merge queue Aug 26, 2026
Merged via the queue into main with commit e4ac08e Aug 26, 2026
16 checks passed
@mehanana
mehanana deleted the 238-send-email-on-Expense-Approval-and-denial branch August 26, 2026 17:23
github-actions Bot added a commit that referenced this pull request Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Send an email on expense approval and denial

3 participants