Skip to content

Deploy with AWS CDK

In this tutorial, you’ll deploy the complete Serverless Inbox system to AWS using Infrastructure-as-Code with CDK.

Time required: ~30 minutes
Difficulty: Medium
Prerequisites: AWS account, Node.js 18+, AWS CLI v2
Last tested: March 2026


By the end of this tutorial:

  • ✅ Clone the CDK repository
  • ✅ Configure your AWS credentials
  • ✅ Deploy all infrastructure with one command
  • ✅ Verify the deployment succeeded
  • ✅ Access your admin dashboard

Before starting, verify you have:

  • AWS Account with admin permissions (or IAM user with broad permissions)
  • Node.js 18+ installed
    Terminal window
    node --version # Should output v18.0.0 or higher
  • AWS CLI v2 installed and configured
    Terminal window
    aws --version # Should output aws-cli/2.x.x or higher
    aws sts get-caller-identity # Should show your AWS account
  • Git installed
    Terminal window
    git --version # Should output git version 2.x.x or higher
  • AWS credentials configured with default region
    Terminal window
    cat ~/.aws/config # Should show default region and profile
  • ~1 hour of time for deployment and initial setup

First, get the source code:

Terminal window
git clone https://github.com/serverless-inbox/cdk.git
cd cdk

Expected output:

Cloning into 'cdk'...
remote: Enumerating objects: 1234, done.
remote: Counting objects: 100% (1234/1234), done.
...
cd cdk # Now inside the repository

Verify you’re in the correct directory:

Terminal window
ls -la

Expected output:

drwxr-xr-x lib/
drwxr-xr-x src/
-rw-r--r-- package.json
-rw-r--r-- tsconfig.json
-rw-r--r-- cdk.json
-rw-r--r-- README.md

Install CDK and project dependencies:

Terminal window
npm install

Expected output:

added 450 packages in 45s

This may take a few minutes depending on internet speed.


The CDK configuration is in cdk.json. Open and review the defaults:

Terminal window
cat cdk.json

Default configuration:

{
"app": "npx ts-node src/main.ts",
"context": {
"region": "us-east-1",
"environment": "dev",
"enableXRayTracing": false,
"emailDomain": "your-domain.com"
}
}

If you want to change settings, edit cdk.json:

Terminal window
# Edit with your preferred editor
nano cdk.json

Common customizations:

  • region - Change to your preferred AWS region (default: us-east-1)
  • environment - Set to “dev”, “staging”, or “prod” (affects naming, logging)
  • emailDomain - Your domain (used for SES configuration, change later if needed)

Tip: For first deployment, stick with defaults. You can customize later.


If this is your first CDK deployment in this AWS account, bootstrap it:

Terminal window
npm run cdk bootstrap

Expected output:

✓ Environment aws://ACCOUNT_ID/us-east-1 bootstrapped.

Note: You only need to do this once per AWS account per region. Future deployments skip this step.


Step 5: Review the Infrastructure Deployment Plan

Section titled “Step 5: Review the Infrastructure Deployment Plan”

Before deploying, see what will be created:

Terminal window
npm run cdk diff

Expected output:

Stack MailboxStack
[+] Resource AWS::Lambda::Function EmailIngestFunction
[+] Resource AWS::DynamoDB::Table EmailTable
[+] Resource AWS::SQS::Queue IndexingQueue
[+] Resource AWS::S3::Bucket SearchIndexBucket
... (many more resources)
Summary: 45 resources to create

Review this output to ensure everything looks correct. See System Architecture if you’re unsure what these resources are for.


Now deploy the infrastructure:

Terminal window
npm run cdk deploy

What happens:

  1. Compiles your CDK code
  2. Uploads deployment package to S3
  3. Creates CloudFormation stack
  4. Deploys all resources
  5. Waits for completion (5-10 minutes)

Expected output:

MailboxStack: creating CloudFormation changeset...
[████████░░] (15/45) MailboxStack: created
Do you wish to deploy these changes (y/n)? y
MailboxStack: deploying... [████████████████████] (45/45)
✓ MailboxStack
Outputs:
MailboxStack.AdminDashboardUrl = https://d123abc.cloudfront.net/admin
MailboxStack.JmapApiUrl = https://api-xyz.execute-api.us-east-1.amazonaws.com
MailboxStack.WebmailUrl = https://d456def.cloudfront.net/webmail
Stack ARN:
arn:aws:cloudformation:us-east-1:ACCOUNT_ID:stack/MailboxStack/UUID

Keep these URLs handy! You’ll need them in the next steps.


Confirm everything deployed successfully:

Terminal window
npm run cdk output

Expected output:

{
"AdminDashboardUrl": "https://d123abc.cloudfront.net/admin",
"JmapApiUrl": "https://api-xyz.execute-api.us-east-1.amazonaws.com",
"WebmailUrl": "https://d456def.cloudfront.net/webmail"
}

Test that the API is responding:

Terminal window
curl https://api-xyz.execute-api.us-east-1.amazonaws.com/.well-known/jmap

Expected output:

{
"capabilities": {
"urn:ietf:params:jmap:core": {}
},
"apiUrl": "https://api-xyz.execute-api.us-east-1.amazonaws.com/jmap",
"eventSourceUrl": "https://api-xyz.execute-api.us-east-1.amazonaws.com/events"
}

If you get a response, your API is working.


Open the Admin Dashboard URL in your browser:

https://d123abc.cloudfront.net/admin

You should see:

  • Login page (Serverless Inbox branding)
  • Ability to log in with initial admin credentials (see notes below)

Note: Initial admin credentials are output during deployment. Check the CloudFormation stack outputs in AWS Console for credentials.


Solution: Node.js not installed or not in PATH

Terminal window
node --version # Should return v18.0.0+
# If not, download from nodejs.org

Solution: Configure AWS CLI

Terminal window
aws configure # Enter access key, secret, region, output format
# Then try again

Issue: “This application requires a newer version of AWS CDK”

Section titled “Issue: “This application requires a newer version of AWS CDK””

Solution: Update CDK

Terminal window
npm install -g aws-cdk
npm install # Reinstall dependencies

Solution: Your AWS user needs permissions for Lambda, DynamoDB, SQS, S3, etc.

Terminal window
# Contact your AWS administrator to grant permissions
# Or use AWS account root credentials for first deployment

Solution: Previous deployment with same name exists

Terminal window
# Option 1: Deploy with different environment name
# Edit cdk.json, change "environment": "dev" to "dev2", redeploy
# Option 2: Delete previous stack and redeploy
aws cloudformation delete-stack --stack-name MailboxStack-dev

Issue: “Timeout - deployment still not complete after 20 minutes”

Section titled “Issue: “Timeout - deployment still not complete after 20 minutes””

Solution: Check CloudFormation events in AWS Console

Terminal window
aws cloudformation describe-stack-events \
--stack-name MailboxStack

Look for failed resources and errors.


Your deployment created:

ComponentAWS ServicePurpose
Email IngestLambdaReceives emails from SES
JMAP APILambda + API GatewayEmail protocol API
Admin APILambda + API GatewayUser management
WebSocketAPI Gateway + LambdaReal-time notifications
Email StorageDynamoDBEmail database
Search IndexEBS VolumeTantivy full-text search
Admin DashboardCloudFront + S3Admin web interface
WebmailCloudFront + S3End-user web interface

See System Architecture for detailed explanation of each component.


Now that Serverless Inbox is deployed:

  1. Complete Initial Setup

    • Verify deployment and configure your account
    • Create admin user
    • Takes ~10 minutes
  2. Configure Email Identity

    • Verify your domain with AWS SES
    • Enable sending/receiving emails
    • Takes ~15 minutes
  3. Manage Users and Roles

    • Invite colleagues
    • Grant permissions
    • Takes ~10 minutes
  4. Try the Webmail UI

    • Send/receive test emails
    • Explore features
    • Takes ~5 minutes

Cleanup (When You’re Done With This Test)

Section titled “Cleanup (When You’re Done With This Test)”

To delete the deployment and stop incurring costs:

Terminal window
npm run cdk destroy

You’ll be asked:

Are you sure you want to delete: MailboxStack (y/n)? y

This removes all AWS resources created. Costs will stop.

Warning: This deletes all data in DynamoDB. Only do this for test deployments.



Congratulations! You’ve successfully deployed Serverless Inbox.

Next: Complete Initial Setup

Last updated: March 2026