- 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.
16 KiB
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/assertfrom 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 testingtest-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
- 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
});
- Import assertions from @std/assert:
import { assert, assertEquals, assertMatch } from '@std/assert';
- Use test helpers:
import { startTestServer, stopTestServer } from '../../helpers/server.loader.ts';
import { connectToSmtp, sendSmtpCommand } from '../../helpers/utils.ts';
- Always cleanup:
- Close connections with
closeSmtpConnection()orconn.close() - Stop test servers with
stopTestServer() - Use try/finally blocks for guaranteed cleanup
- 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
netmodule - After: Deno
Deno.connect()/Deno.listen()
Imports
- Before:
.jsextensions, Node-style imports - After:
.tsextensions, 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:
- Port SEC-01: Authentication test
- Port SEC-08: Rate Limiting test
- Port SEC-10: Header Injection Prevention test
- 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:
- Maintain test IDs and organization
- Convert to Deno.test() format
- Use @std/assert for assertions
- Update imports to .ts extensions
- Use Deno-native TCP connections
- Preserve test logic and validations
- Add
sanitizeResources: false, sanitizeOps: falsefor network tests - Update this README with ported tests