Files
mailer/test
Juergen Kunz 6523c55516 feat: Implement Deno-native STARTTLS handler and connection wrapper
- Refactored STARTTLS implementation to use Deno's native TLS via Deno.startTls().
- Introduced ConnectionWrapper to provide a Node.js net.Socket-compatible interface for Deno.Conn and Deno.TlsConn.
- Updated TlsHandler to utilize the new STARTTLS implementation.
- Added comprehensive SMTP authentication tests for PLAIN and LOGIN mechanisms.
- Implemented rate limiting tests for SMTP server connections and commands.
- Enhanced error handling and logging throughout the STARTTLS and connection upgrade processes.
2025-10-28 18:51:33 +00:00
..

Mailer SMTP Test Suite (Deno)

Comprehensive SMTP server and client test suite ported from dcrouter to Deno-native testing.

Test Framework

  • Framework: Deno native testing (Deno.test)
  • Assertions: @std/assert from Deno standard library
  • Run Command: deno test --allow-all --no-check test/
  • Run Single Test: deno test --allow-all --no-check test/suite/smtpserver_commands/test.cmd-01.ehlo-command.test.ts

Test Infrastructure

Helpers (test/helpers/)

  • server.loader.ts - Test SMTP server lifecycle management

    • Start/stop test servers with configurable options
    • TLS certificate handling
    • Mock email processing
    • Port management utilities
  • utils.ts - SMTP protocol test utilities

    • TCP connection management (Deno-native)
    • SMTP command sending/receiving
    • Protocol handshake helpers
    • MIME message creation
    • Retry and timing utilities
  • smtp.client.ts - SMTP client test utilities

    • Test client creation with various configurations
    • Email sending helpers
    • Connection pooling testing
    • Throughput measurement

Fixtures (test/fixtures/)

  • test-cert.pem - Self-signed certificate for TLS testing
  • test-key.pem - Private key for TLS testing

Test Suite Organization

All tests follow the naming convention: test.<category-id>.<description>.test.ts

Test Categories

1. Connection Management (CM) - smtpserver_connection/

Tests for SMTP connection handling, TLS support, and connection lifecycle.

ID Test Priority Status
CM-01 TLS Connection High PORTED
CM-02 Multiple Simultaneous Connections High Planned
CM-03 Connection Timeout High Planned
CM-06 STARTTLS Upgrade High Planned
CM-10 Plain Connection Low Planned

2. SMTP Commands (CMD) - smtpserver_commands/

Tests for SMTP protocol command implementation.

ID Test Priority Status
CMD-01 EHLO Command High PORTED
CMD-02 MAIL FROM Command High PORTED
CMD-03 RCPT TO Command High PORTED
CMD-04 DATA Command High PORTED
CMD-06 RSET Command Medium PORTED
CMD-13 QUIT Command High PORTED

3. Email Processing (EP) - smtpserver_email-processing/

Tests for email content handling, parsing, and delivery.

ID Test Priority Status
EP-01 Basic Email Sending High PORTED
EP-02 Invalid Email Address Handling High Planned
EP-04 Large Email Handling High Planned
EP-05 MIME Handling High Planned

4. Security (SEC) - smtpserver_security/

Tests for security features and protections.

ID Test Priority Status
SEC-01 Authentication High PORTED
SEC-03 DKIM Processing High Planned
SEC-04 SPF Checking High Planned
SEC-06 IP Reputation Checking High PORTED
SEC-08 Rate Limiting High Planned
SEC-10 Header Injection Prevention High Planned

5. Error Handling (ERR) - smtpserver_error-handling/

Tests for proper error handling and recovery.

ID Test Priority Status
ERR-01 Syntax Error Handling High PORTED
ERR-02 Invalid Sequence Handling High PORTED
ERR-05 Resource Exhaustion High Planned
ERR-07 Exception Handling High Planned

Currently Ported Tests

CMD-01: EHLO Command (test.cmd-01.ehlo-command.test.ts)

Tests: 5 total (5 passing)

  • Server startup/shutdown
  • EHLO response with proper capabilities
  • Invalid hostname handling
  • Command pipelining (multiple EHLO)

Key validations:

  • ✓ Server advertises SIZE capability
  • ✓ Server advertises 8BITMIME capability
  • ✓ Last capability line uses "250 " (space, not hyphen)
  • ✓ Server handles invalid hostnames gracefully
  • ✓ Second EHLO resets session state

CMD-02: MAIL FROM Command (test.cmd-02.mail-from.test.ts)

Tests: 6 total (6 passing)

  • Valid sender address acceptance
  • Invalid sender address rejection
  • SIZE parameter support
  • Command sequence enforcement

Key validations:

  • ✓ Accepts valid email formats
  • ✓ Accepts IP literals (user@[192.168.1.1])
  • ✓ Rejects malformed addresses
  • ✓ Supports SIZE parameter
  • ✓ Enforces EHLO before MAIL FROM

CMD-03: RCPT TO Command (test.cmd-03.rcpt-to.test.ts)

Tests: 7 total (7 passing)

  • Valid recipient address acceptance
  • Multiple recipients support
  • Invalid recipient address rejection
  • Command sequence enforcement
  • RSET clears recipients

Key validations:

  • ✓ Accepts valid recipient formats
  • ✓ Accepts IP literals and subdomains
  • ✓ Supports multiple recipients per transaction
  • ✓ Rejects invalid email addresses
  • ✓ Enforces RCPT TO after MAIL FROM
  • ✓ RSET properly clears recipient list

CMD-04: DATA Command (test.cmd-04.data-command.test.ts)

Tests: 7 total (7 passing)

  • Email data transmission after RCPT TO
  • Rejection without RCPT TO
  • Dot-stuffing handling
  • Large message support
  • Command sequence enforcement

Key validations:

  • ✓ Accepts email data with proper terminator
  • ✓ Returns 354 to start data input
  • ✓ Returns 250 after successful email acceptance
  • ✓ Rejects DATA without MAIL FROM
  • ✓ Handles dot-stuffed content correctly
  • ✓ Supports large messages (10KB+)

CMD-06: RSET Command (test.cmd-06.rset-command.test.ts)

Tests: 8 total (8 passing)

  • RSET after MAIL FROM
  • RSET after RCPT TO
  • Multiple consecutive RSET commands
  • RSET without active transaction
  • RSET clears all recipients
  • RSET with parameters (ignored)

Key validations:

  • ✓ Responds with 250 OK
  • ✓ Resets transaction state after MAIL FROM
  • ✓ Clears recipients requiring new MAIL FROM
  • ✓ Idempotent (multiple RSETs work)
  • ✓ Works without active transaction
  • ✓ Clears all recipients from transaction
  • ✓ Ignores parameters as per RFC

CMD-13: QUIT Command (test.cmd-13.quit-command.test.ts)

Tests: 7 total (7 passing)

  • Graceful connection termination
  • QUIT after MAIL FROM
  • QUIT after complete transaction
  • Idempotent QUIT handling
  • Immediate QUIT without EHLO

Key validations:

  • ✓ Returns 221 Service closing
  • ✓ Works at any point in SMTP session
  • ✓ Properly closes connection
  • ✓ Handles multiple QUIT commands gracefully
  • ✓ Allows immediate QUIT after greeting

CM-01: TLS Connection (test.cm-01.tls-connection.test.ts)

Tests: 8 total (8 passing)

  • Server advertises STARTTLS capability
  • STARTTLS command initiates upgrade
  • Direct TLS connection support
  • STARTTLS not available after already started
  • STARTTLS requires EHLO first
  • Connection accepts commands after TLS
  • Server lifecycle management

Key validations:

  • ✓ STARTTLS advertised in EHLO capabilities
  • ✓ STARTTLS command responds with 220 Ready
  • ✓ Direct TLS connections work (with self-signed certs)
  • ✓ Second STARTTLS properly rejected
  • ✓ STARTTLS before EHLO handled correctly
  • ✓ TLS upgrade process validated

EP-01: Basic Email Sending (test.ep-01.basic-email-sending.test.ts)

Tests: 7 total (7 passing)

  • Complete SMTP transaction flow (CONNECT → EHLO → MAIL FROM → RCPT TO → DATA → CONTENT → QUIT)
  • Email with MIME attachment (multipart/mixed)
  • HTML email (multipart/alternative)
  • Email with custom headers (X-Custom-Header, X-Priority, Reply-To, etc.)
  • Minimal email (body only, no headers)
  • Server lifecycle management

Key validations:

  • ✓ Complete email lifecycle from greeting to QUIT
  • ✓ MIME multipart messages with attachments
  • ✓ HTML email with plain text fallback
  • ✓ Custom header support (X-*, Reply-To, Organization)
  • ✓ Minimal email content accepted
  • ✓ Email queuing and processing confirmed

SEC-06: IP Reputation Checking (test.sec-06.ip-reputation.test.ts)

Tests: 7 total (7 passing)

  • IP reputation check accepts localhost connections
  • Known good senders accepted
  • Multiple connections from same IP handled
  • Complete SMTP flow with reputation check
  • Infrastructure placeholder test
  • Server lifecycle management

Key validations:

  • ✓ IP reputation infrastructure in place
  • ✓ Localhost connections accepted after reputation check
  • ✓ Legitimate senders and recipients accepted
  • ✓ Multiple concurrent connections handled properly
  • ✓ Complete email transaction works with IP checks
  • ✓ IPReputationChecker class exists (placeholder implementation)

Note: Current implementation uses placeholder IP reputation checker that accepts all legitimate traffic. Infrastructure is ready for future implementation of real IP reputation databases, blacklist checking, and suspicious pattern detection.

ERR-01: Syntax Error Handling (test.err-01.syntax-errors.test.ts)

Tests: 10 total (10 passing)

  • Rejects invalid commands
  • Rejects MAIL FROM without brackets
  • Rejects RCPT TO without brackets
  • Rejects EHLO without hostname
  • Handles commands with extra parameters
  • Rejects malformed email addresses
  • Rejects commands in wrong sequence
  • Handles excessively long commands
  • Server lifecycle management

Key validations:

  • ✓ Invalid commands rejected with 500/502 error codes
  • ✓ MAIL FROM requires angle brackets (501 error if missing)
  • ✓ RCPT TO requires angle brackets (501 error if missing)
  • ✓ EHLO requires hostname parameter (501 error if missing)
  • ✓ Extra parameters on QUIT handled (501 syntax error)
  • ✓ Malformed email addresses rejected (501 error)
  • ✓ Commands in wrong sequence rejected (503 error)
  • ✓ Excessively long commands handled gracefully

ERR-02: Invalid Sequence Handling (test.err-02.invalid-sequence.test.ts)

Tests: 10 total (10 passing)

  • Rejects MAIL FROM before EHLO
  • Rejects RCPT TO before MAIL FROM
  • Rejects DATA before RCPT TO (RFC 5321 compliance)
  • Allows multiple EHLO commands
  • Handles second MAIL FROM without RSET
  • Rejects DATA without MAIL FROM
  • Handles commands after QUIT
  • Recovers from syntax errors in sequence
  • Server lifecycle management

Key validations:

  • ✓ MAIL FROM requires EHLO first (503 error if missing)
  • ✓ RCPT TO requires MAIL FROM first (503 error if missing)
  • ✓ DATA requires RCPT TO with at least one recipient (503 error if missing)
  • ✓ Multiple EHLO commands allowed (resets session state)
  • ✓ Commands after QUIT handled correctly (connection closed)
  • ✓ Session recovers from syntax errors without terminating
  • ✓ RFC 5321 compliance: strict command sequence enforcement

Running Tests

Run All Tests

deno test --allow-all --no-check test/

Run Specific Category

# SMTP commands tests
deno test --allow-all --no-check test/suite/smtpserver_commands/

# Connection tests
deno test --allow-all --no-check test/suite/smtpserver_connection/

Run Single Test File

deno test --allow-all --no-check test/suite/smtpserver_commands/test.cmd-01.ehlo-command.test.ts

Run with Verbose Output

deno test --allow-all --no-check --trace-leaks test/

Test Development Guidelines

Writing New Tests

  1. Use Deno.test() format:
Deno.test({
  name: 'CMD-XX: Description of test',
  async fn() {
    // Test implementation
  },
  sanitizeResources: false,  // Required for network tests
  sanitizeOps: false,        // Required for network tests
});
  1. Import assertions from @std/assert:
import { assert, assertEquals, assertMatch } from '@std/assert';
  1. Use test helpers:
import { startTestServer, stopTestServer } from '../../helpers/server.loader.ts';
import { connectToSmtp, sendSmtpCommand } from '../../helpers/utils.ts';
  1. Always cleanup:
  • Close connections with closeSmtpConnection() or conn.close()
  • Stop test servers with stopTestServer()
  • Use try/finally blocks for guaranteed cleanup
  1. Test isolation:
  • Each test file uses its own port (e.g., CMD-01 uses 25251, CMD-02 uses 25252)
  • Setup and cleanup tests ensure clean state

Key Differences from dcrouter Tests

Framework

  • Before: @git.zone/tstest/tapbundle (Node.js)
  • After: Deno.test (native)

Assertions

  • Before: expect(x).toBeTruthy(), expect(x).toEqual(y)
  • After: assert(x), assertEquals(x, y), assertMatch(x, regex)

Network I/O

  • Before: Node.js net module
  • After: Deno Deno.connect() / Deno.listen()

Imports

  • Before: .js extensions, Node-style imports
  • After: .ts extensions, Deno-style imports

Test Priorities

Phase 1: Core SMTP Functionality (High Priority) COMPLETE

  • CMD-01: EHLO Command
  • CMD-02: MAIL FROM Command
  • CMD-03: RCPT TO Command
  • CMD-04: DATA Command
  • CMD-13: QUIT Command
  • CM-01: TLS Connection
  • EP-01: Basic Email Sending

Phase 2: Security & Validation (High Priority)

  • 🔄 SEC-01: Authentication
  • SEC-06: IP Reputation
  • 🔄 SEC-08: Rate Limiting
  • 🔄 SEC-10: Header Injection Prevention
  • ERR-01: Syntax Error Handling
  • ERR-02: Invalid Sequence Handling

Phase 3: Advanced Features (Medium Priority)

  • 🔄 SEC-03: DKIM Processing
  • 🔄 SEC-04: SPF Checking
  • 🔄 EP-04: Large Email Handling
  • 🔄 EP-05: MIME Handling
  • 🔄 CM-02: Multiple Connections
  • 🔄 CM-06: STARTTLS Upgrade

Phase 4: Complete Coverage (All Remaining)

  • All performance tests
  • All reliability tests
  • All edge case tests
  • All RFC compliance tests
  • SMTP client tests

Current Status

Infrastructure: Complete

  • Deno-native test helpers (utils.ts, server.loader.ts, smtp.client.ts)
  • Server lifecycle management
  • SMTP protocol utilities with readSmtpResponse helper
  • Test certificates (self-signed RSA)

Tests Ported: 11/100+ test files (82 total tests passing)

  • CMD-01: EHLO Command (5 tests passing)
  • CMD-02: MAIL FROM Command (6 tests passing)
  • CMD-03: RCPT TO Command (7 tests passing)
  • CMD-04: DATA Command (7 tests passing)
  • CMD-06: RSET Command (8 tests passing)
  • CMD-13: QUIT Command (7 tests passing)
  • CM-01: TLS Connection (8 tests passing)
  • EP-01: Basic Email Sending (7 tests passing)
  • SEC-06: IP Reputation Checking (7 tests passing)
  • ERR-01: Syntax Error Handling (10 tests passing)
  • ERR-02: Invalid Sequence Handling (10 tests passing)

Coverage: Complete essential SMTP transaction flow

  • EHLO → MAIL FROM → RCPT TO → DATA → QUIT
  • TLS/STARTTLS support
  • Complete email lifecycle (MIME, HTML, custom headers)

Phase 1 Status: COMPLETE (7/7 tests, 100%)

Phase 2 Status: 🔄 IN PROGRESS (3/6 tests, 50%)

  • SEC-06: IP Reputation
  • ERR-01: Syntax Errors
  • ERR-02: Invalid Sequence
  • 🔄 SEC-01: Authentication
  • 🔄 SEC-08: Rate Limiting
  • 🔄 SEC-10: Header Injection

Next Steps:

  1. Port SEC-01: Authentication test
  2. Port SEC-08: Rate Limiting test
  3. Port SEC-10: Header Injection Prevention test
  4. Continue with Phase 3 (Advanced Features)

Production Readiness Criteria

Gate 1: Core Functionality (>90% tests passing)

  • Basic SMTP command handling
  • Connection management
  • Email delivery
  • Error handling

Gate 2: Security (>95% tests passing)

  • Authentication mechanisms
  • TLS/STARTTLS support
  • Rate limiting
  • Injection prevention

Gate 3: Enterprise Ready (>85% tests passing)

  • Full RFC compliance
  • Performance under load
  • Advanced security features
  • Complete edge case handling

Contributing

When porting tests from dcrouter:

  1. Maintain test IDs and organization
  2. Convert to Deno.test() format
  3. Use @std/assert for assertions
  4. Update imports to .ts extensions
  5. Use Deno-native TCP connections
  6. Preserve test logic and validations
  7. Add sanitizeResources: false, sanitizeOps: false for network tests
  8. Update this README with ported tests

Resources