A serverless Discord bot for email verification using AWS Lambda, DynamoDB, and SES. Supports multi-guild configuration with custom email domains and verification messages.
Deploy the entire AWS infrastructure in one command:
# Configure AWS CLI
aws configure
# Clone and run setup
git clone https://github.com/offsetkeyz/discord-email-verification-bot.git
cd discord-email-verification-bot
./setup-aws.shThe automated setup script handles everything: DynamoDB tables, Lambda function, API Gateway, SES, IAM roles, and slash command registration. Setup time: ~5 minutes.
See Setup for detailed instructions.
- 🚀 One-Command Deployment - Automated
setup-aws.shscript deploys entire infrastructure - Serverless Architecture - Runs on AWS Lambda with API Gateway webhook
- Multi-Guild Support - Each Discord server can configure their own:
- Allowed email domains
- Verified role
- Custom verification message with emoji support
- Email Verification - 6-digit codes sent via AWS SES
- Security Features:
- Request signature verification
- Rate limiting (60-second cooldown between attempts)
- Code expiration (15 minutes)
- Maximum 3 verification attempts per code
- Admin Setup Flow - Interactive
/setup-email-verificationcommand for server configuration - Persistent Storage - DynamoDB for session and verification tracking
- Lambda - Bot logic and interaction handling
- DynamoDB - Three tables:
discord-verification-sessions- Active verification sessions (with TTL)discord-verification-records- Permanent verification recordsdiscord-guild-configs- Per-guild configuration
- API Gateway - HTTP webhook endpoint for Discord interactions
- SES - Email delivery for verification codes
- SSM Parameter Store - Secure storage for bot token
lambda/
├── lambda_function.py # Main Lambda handler and routing
├── handlers.py # Verification flow handlers
├── setup_handler.py # /setup-email-verification command handlers
├── discord_interactions.py # Discord API interaction types
├── discord_api.py # Discord API calls (roles, messages)
├── dynamodb_operations.py # DynamoDB operations
├── ses_email.py # AWS SES email sending
├── verification_logic.py # Pure verification logic functions
├── guild_config.py # Guild configuration management
└── ssm_utils.py # AWS SSM parameter store utils
setup-aws.sh # Automated AWS deployment script
register_slash_commands.py # Script to register slash commands
- AWS Account with permissions to create:
- Lambda functions
- DynamoDB tables
- SES verified email identity
- IAM roles and policies
- SSM parameters
- API Gateway endpoints
- Discord Application from Discord Developer Portal
- Python 3.11 (for local development/testing)
- Go to Discord Developer Portal
- Create a new application
- Go to the "Bot" tab:
- Reset token and copy it (save as
DISCORD_TOKEN) - Enable these privileged intents:
- Server Members Intent (required)
- Message Content Intent (required for message link feature)
- Reset token and copy it (save as
- Go to "General Information":
- Copy Application ID (save as
DISCORD_APP_ID) - Copy Public Key (save as
DISCORD_PUBLIC_KEY)
- Copy Application ID (save as
- Go to "OAuth2" > "URL Generator":
- Select scopes:
bot,applications.commands - Select permissions:
- Read Messages/View Channels
- Send Messages
- Manage Roles
- Copy the URL and invite bot to your server
- Select scopes:
Choose one of the following setup methods:
We provide a setup script that automates the entire AWS deployment:
# Make sure you have AWS CLI configured
aws configure
# Run the setup script
./setup-aws.shThe script will:
- âś… Create all DynamoDB tables with proper schemas
- âś… Set up SES email verification
- âś… Create IAM role with appropriate permissions
- âś… Store bot token in SSM Parameter Store
- âś… Create Lambda function and layer
- âś… Set up API Gateway endpoint
- âś… Register Discord slash commands
- âś… Provide you with the webhook URL to configure in Discord
Time to complete: ~5-10 minutes (mostly waiting for AWS resources)
After the script completes, follow the "Next Steps" it provides to finish Discord configuration.
If you prefer to set up AWS resources manually, follow these detailed instructions:
# Sessions table (for active verification sessions)
aws dynamodb create-table \
--table-name discord-verification-sessions \
--attribute-definitions \
AttributeName=user_id,AttributeType=S \
AttributeName=guild_id,AttributeType=S \
--key-schema \
AttributeName=user_id,KeyType=HASH \
AttributeName=guild_id,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST
# Enable TTL for auto-cleanup
aws dynamodb update-time-to-live \
--table-name discord-verification-sessions \
--time-to-live-specification "Enabled=true, AttributeName=ttl"
# Records table (for permanent verification records)
aws dynamodb create-table \
--table-name discord-verification-records \
--attribute-definitions \
AttributeName=verification_id,AttributeType=S \
AttributeName=created_at,AttributeType=N \
AttributeName=user_guild_composite,AttributeType=S \
--key-schema \
AttributeName=verification_id,KeyType=HASH \
AttributeName=created_at,KeyType=RANGE \
--global-secondary-indexes \
"[{\"IndexName\":\"user_guild-index\",\"KeySchema\":[{\"AttributeName\":\"user_guild_composite\",\"KeyType\":\"HASH\"},{\"AttributeName\":\"created_at\",\"KeyType\":\"RANGE\"}],\"Projection\":{\"ProjectionType\":\"ALL\"}}]" \
--billing-mode PAY_PER_REQUEST
# Guild configs table
aws dynamodb create-table \
--table-name discord-guild-configs \
--attribute-definitions \
AttributeName=guild_id,AttributeType=S \
--key-schema \
AttributeName=guild_id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST# Verify your email address in SES
aws ses verify-email-identity --email-identity noreply@yourdomain.com
# Check verification status
aws ses get-identity-verification-attributes \
--identities noreply@yourdomain.com
# Request production access (to send to any email)
# Go to AWS Console > SES > Account Dashboard > Request production accessCreate a role discord-verification-lambda-role with this policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:UpdateItem",
"dynamodb:DeleteItem",
"dynamodb:Query",
"dynamodb:Scan"
],
"Resource": [
"arn:aws:dynamodb:*:*:table/discord-verification-sessions",
"arn:aws:dynamodb:*:*:table/discord-verification-records",
"arn:aws:dynamodb:*:*:table/discord-verification-records/index/*",
"arn:aws:dynamodb:*:*:table/discord-guild-configs"
]
},
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ssm:GetParameter"
],
"Resource": "arn:aws:ssm:*:*:parameter/discord-bot/*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}aws ssm put-parameter \
--name /discord-bot/token \
--value "YOUR_DISCORD_BOT_TOKEN" \
--type SecureString# Create deployment package
cd lambda
zip -r ../lambda-deployment.zip *.py
cd ..
# Create Lambda function
aws lambda create-function \
--function-name discord-verification-handler \
--runtime python3.11 \
--role arn:aws:iam::YOUR_ACCOUNT_ID:role/discord-verification-lambda-role \
--handler lambda_function.lambda_handler \
--zip-file fileb://lambda-deployment.zip \
--timeout 30 \
--memory-size 512 \
--environment "Variables={
DYNAMODB_SESSIONS_TABLE=discord-verification-sessions,
DYNAMODB_RECORDS_TABLE=discord-verification-records,
DYNAMODB_GUILD_CONFIGS_TABLE=discord-guild-configs,
DISCORD_PUBLIC_KEY=YOUR_PUBLIC_KEY,
FROM_EMAIL=noreply@yourdomain.com
}"
# Create Lambda layer for dependencies
pip install -r requirements.txt -t python/
zip -r discord-bot-dependencies.zip python/
aws lambda publish-layer-version \
--layer-name discord-bot-dependencies \
--zip-file fileb://discord-bot-dependencies.zip \
--compatible-runtimes python3.11
# Attach layer to function
aws lambda update-function-configuration \
--function-name discord-verification-handler \
--layers arn:aws:lambda:REGION:ACCOUNT_ID:layer:discord-bot-dependencies:1- Go to API Gateway Console
- Create HTTP API
- Add integration to Lambda function
discord-verification-handler - Create route:
POST /interactions - Deploy API and copy the invoke URL
- Go back to Discord Developer Portal
- Go to "General Information"
- Set "Interactions Endpoint URL" to:
https://YOUR_API_GATEWAY_URL/interactions - Discord will verify the endpoint (signature verification must be working)
Note: If you used the automated setup script (./setup-aws.sh), this step is already done. Skip to Usage.
For manual setup only:
# Create .env file
cp .env.example .env
# Edit .env with your values
nano .env
# Register commands
python3 register_slash_commands.pyRun /setup-email-verification to configure the bot for your server:
- Select Role - Choose which role to assign when users verify
- Select Channel - Choose which channel to post the verification message
- Enter Domains - Specify allowed email domains (e.g.,
yourschool.edu) - Create Message - Either:
- Create a message in Discord with emojis and copy the message link
- Or skip to keep the existing message (when reconfiguring)
- Preview & Approve - Review the configuration before it goes live
- Click the "Start Verification" button in the verification message
- Enter your .edu email address
- Check your email for a 6-digit code
- Click "Submit Code" and enter the code
- Get the verified role automatically!
# Clone repository
git clone https://github.com/yourusername/au-discord-bot.git
cd au-discord-bot
# Install dependencies
pip install -r requirements.txt
# Configure environment
cp .env.example .env
# Edit .env with your credentials
# Test locally (requires AWS credentials configured)
# Lambda can be tested with sam local or directly in AWS# Create deployment package
python3 -m zipfile -c lambda-deployment.zip lambda/*.py
# Update Lambda function
aws lambda update-function-code \
--function-name discord-verification-handler \
--zip-file fileb://lambda-deployment.zip
# Tail logs to verify
aws logs tail /aws/lambda/discord-verification-handler --follow# View recent logs
aws logs tail /aws/lambda/discord-verification-handler --follow
# Check Lambda metrics
aws cloudwatch get-metric-statistics \
--namespace AWS/Lambda \
--metric-name Invocations \
--dimensions Name=FunctionName,Value=discord-verification-handler \
--start-time 2024-01-01T00:00:00Z \
--end-time 2024-01-02T00:00:00Z \
--period 3600 \
--statistics Sum
# Query DynamoDB
aws dynamodb scan --table-name discord-guild-configs
aws dynamodb scan --table-name discord-verification-records- Check Lambda logs for errors
- Verify signature verification is working
- Ensure Lambda has correct environment variables
- Check API Gateway integration
- Verify SES email identity is verified
- Check SES is in production mode (not sandbox)
- Review Lambda logs for SES errors
- Ensure IAM role has SES permissions
- Check bot has "Manage Roles" permission
- Ensure bot's role is ABOVE the verified role in hierarchy
- Verify role ID is correct in guild config
- Check Lambda has SSM parameter store access for bot token
- Users can only start verification once per 60 seconds
- This prevents spam and protects the email service
- Wait for the cooldown period to expire
- Bot token stored securely in SSM Parameter Store
- Request signature verification prevents unauthorized requests
- Rate limiting prevents abuse
- DynamoDB TTL auto-deletes old sessions
- Email addresses stored only for verification records
- All secrets in environment variables or SSM (never in code)
With typical usage (100 verifications/month):
- Lambda: ~$0.20/month (generous estimate)
- DynamoDB: ~$0.25/month (on-demand pricing)
- SES: $0.10/1000 emails = ~$0.01/month
- API Gateway: ~$0.01/month
- Total: < $1/month
Comprehensive documentation is organized in the docs/ directory:
- Deployment Checklist - Step-by-step deployment guide
- Discord Testing Guide - Testing procedures and workflows
- SES Deployment Checklist - AWS SES setup and configuration
- Setup Script Usage - How to use the automated setup script
- SES Compliance Quick Reference - SES compliance guidelines
- Testing Quick Reference - Quick testing commands and tips
- SES Operations Runbook - Production operations for SES
- SES Setup Guide - Complete SES configuration guide
- SES Testing Guide - Testing SES email delivery
Historical implementation docs and completed features are in docs/archive/:
docs/archive/features/- Feature implementation summariesdocs/archive/development/- Development roadmaps and summariesdocs/archive/testing-phase/- Test reports and resultsdocs/archive/fixes/- Historical bug fixes and patches
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
[Add your license here]
For issues or questions:
- Check Lambda logs in CloudWatch
- Review Discord bot permissions
- Verify AWS resources are correctly configured
- Open an issue on GitHub