FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
paulkinlan
paulkinlanpostherous
https://posthero.us - an email powered blogging system
Public
Like
6
postherous
Home
Code
22
backend
3
frontend
2
shared
2
.vtignore
ACTIVITYPUB-STATUS.md
ACTIVITYPUB-TROUBLESHOOTING.md
ACTIVITYPUB.md
README.md
SECURITY.md
SETUP.md
H
debug-config.ts
H
debug-signatures.ts
deno.json
E
email.ts
H
generate-keys.ts
H
test-activitypub-delivery.ts
H
test-activitypub-inbox.ts
H
test-activitypub.ts
H
test-follow.ts
H
test-http-signatures.ts
H
test-publish.ts
H
test-verification.ts
Branches
1
Pull requests
Remixes
4
History
Environment variables
9
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data โ€“ all from the browser, and deployed in milliseconds.
Sign up now
Code
/
SECURITY.md
Code
/
SECURITY.md
Search
7/11/2025
Viewing readonly version of main branch: v369
View latest version
SECURITY.md

Email Blog Security Configuration

Overview

The email blog platform includes robust security features to prevent unauthorized posting and email spoofing. This guide explains how to configure and use these security features.

Required Configuration

1. Set Allowed Email Addresses

Configure the ALLOWED_EMAIL_ADDRESSES environment variable with a comma-separated list of email addresses that are allowed to publish posts:

ALLOWED_EMAIL_ADDRESSES=user1@example.com,user2@example.com,admin@myblog.com

Important Notes:

  • Email addresses are case-insensitive
  • Whitespace around commas is automatically trimmed
  • If this variable is not set, no emails will be allowed
  • Only exact email matches are allowed (no wildcards or domains)

2. Set Base URL (Optional)

Set your blog's base URL for verification links:

BASE_URL=https://your-blog.web.val.run

If not set, the system will auto-detect the URL from incoming requests.

How Email Security Works

Step 1: Email Allowlist Check

When an email is received:

  1. The sender's email address is checked against ALLOWED_EMAIL_ADDRESSES
  2. If not allowed, the email is ignored (logged but not processed)
  3. If allowed, the process continues to verification

Step 2: Draft Creation

For allowed emails:

  1. Post content is extracted from the email
  2. A draft post is created (not published yet)
  3. A unique verification token is generated
  4. The draft expires after 24 hours if not verified

Step 3: Verification Email

  1. An automated verification email is sent to the original sender
  2. The email contains a secure verification link
  3. The link expires after 24 hours for security

Step 4: Verification and Publishing

When the sender clicks the verification link:

  1. The token is validated and checked for expiration
  2. The email verification is marked as complete
  3. The draft post is converted to a published post
  4. External services are notified (RSS, ActivityPub, etc.)
  5. The draft and verification records are cleaned up

Security Benefits

Anti-Spoofing Protection

  • Email confirmation required: Even if someone spoofs your email address, they can't access your email to click the verification link
  • Time-limited tokens: Verification links expire after 24 hours
  • One-time use: Each verification token can only be used once

Access Control

  • Allowlist-based: Only pre-approved email addresses can publish
  • No wildcards: Exact email matching prevents subdomain attacks
  • Easy management: Add/remove allowed emails via environment variable

Automatic Cleanup

  • Expired drafts: Unverified drafts are automatically deleted after 24 hours
  • Token cleanup: Used and expired verification tokens are removed
  • Database efficiency: Regular cleanup prevents database bloat

Email Templates

Verification Email Template

The system sends a professional verification email with:

  • Clear subject line indicating verification needed
  • HTML and plain text versions
  • Secure verification link
  • Expiration warning (24 hours)
  • Instructions for non-senders to ignore

Example Verification Email

Subject: Verify your blog post: My Amazing Blog Post

Hello,

We received a blog post submission with the title "My Amazing Blog Post" from this email address.

To confirm that you sent this post and publish it to the blog, please click the verification link below:

[Verify and Publish Post]

Important: This verification link will expire in 24 hours for security reasons.

If you did not send this blog post, please ignore this email.

Troubleshooting

Email Not Processing

  1. Check allowlist: Ensure sender email is in ALLOWED_EMAIL_ADDRESSES
  2. Check logs: Look for "Email from X is not in the allowed list" messages
  3. Verify format: Ensure environment variable is properly formatted

Verification Link Issues

  1. Check expiration: Links expire after 24 hours
  2. Check BASE_URL: Ensure it's set correctly or auto-detection is working
  3. One-time use: Each link can only be used once

Posts Not Publishing

  1. Click verification link: Posts remain as drafts until verified
  2. Check email delivery: Ensure verification emails aren't in spam
  3. Check token validity: Tokens expire after 24 hours

Best Practices

Email Management

  • Use dedicated email addresses for blog posting
  • Keep the allowlist minimal (only trusted users)
  • Regularly review who has posting access

Security Monitoring

  • Monitor logs for unauthorized posting attempts
  • Review verification patterns for unusual activity
  • Keep environment variables secure

Backup Strategy

  • Regular database backups include draft posts
  • Consider notification systems for failed verifications
  • Document your allowed email addresses

API Endpoints

Verification Endpoint

  • URL: GET /verify-email?token=<verification_token>
  • Purpose: Handles email verification and post publishing
  • Responses:
    • 200: Successful verification and publishing
    • 400: Missing or invalid token
    • 404: Token not found
    • 410: Token expired
    • 500: Server error during publishing

Security Headers

All verification pages include:

  • Proper HTML escaping to prevent XSS
  • Responsive design for mobile verification
  • Clear success/error messaging
  • Links back to the main blog

Migration from Unsecured Version

If upgrading from a version without security:

  1. Set environment variables before receiving new emails
  2. Existing posts remain published (not affected)
  3. New emails will require verification from the first email received
  4. Test thoroughly with a test email before going live

Security is enabled by default. Configure ALLOWED_EMAIL_ADDRESSES to start receiving posts!

Go to top
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Product
FeaturesPricing
Developers
DocsStatusAPI ExamplesNPM Package Examples
Explore
ShowcaseTemplatesNewest ValsTrending ValsNewsletter
Company
AboutBlogCareersBrandhi@val.town
Terms of usePrivacy policyAbuse contact
ยฉ 2025 Val Town, Inc.