SMTP Testing Guide

Updated February 14, 2024

Learn how to effectively test SMTP email functionality with Mail7's comprehensive testing infrastructure. This guide covers everything from basic SMTP testing concepts to advanced implementation strategies.

Understanding SMTP Testing

SMTP (Simple Mail Transfer Protocol) testing is crucial for ensuring reliable email delivery in your applications. Key aspects include:

  • Connection Testing: Verify SMTP server connectivity and authentication
  • Message Delivery: Validate successful email transmission
  • Error Handling: Test responses to various SMTP scenarios
  • Performance: Measure email delivery speed and reliability

Mail7 SMTP Testing Features

  • SMTP Server Access: Dedicated testing servers for your applications
  • Real-time Monitoring: Track email delivery and server responses
  • Multiple Authentication Methods: Support for various SMTP authentication protocols
  • Detailed Logging: Comprehensive logs for debugging and analysis

Implementation Guide

1. Basic SMTP Connection Test


const nodemailer = require('nodemailer');

// Create SMTP transport
const transporter = nodemailer.createTransport({
    host: 'smtp.mail7.io',
    port: 587,
    secure: false,
    auth: {
        user: 'your-username',
        pass: 'your-password'
    }
});

// Verify connection
async function testConnection() {
    try {
        await transporter.verify();
        console.log('SMTP connection successful');
    } catch (error) {
        console.error('SMTP connection failed:', error);
    }
}
                

2. Sending Test Email


async function sendTestEmail() {
    try {
        const info = await transporter.sendMail({
            from: '[email protected]',
            to: '[email protected]',
            subject: 'SMTP Test Email',
            text: 'This is a test email from Mail7',
            html: '

This is a test email from Mail7

' }); console.log('Message sent:', info.messageId); } catch (error) { console.error('Send failed:', error); } }

3. Error Handling and Retry Logic


class SMTPClient {
    constructor(config) {
        this.config = config;
        this.maxRetries = config.maxRetries || 3;
        this.retryDelay = config.retryDelay || 1000;
    }

    async createTransport() {
        return nodemailer.createTransport({
            host: this.config.host,
            port: this.config.port,
            secure: this.config.secure,
            auth: {
                user: this.config.username,
                pass: this.config.password
            },
            tls: {
                rejectUnauthorized: true,
                minVersion: 'TLSv1.2'
            }
        });
    }

    async sendWithRetry(mailOptions) {
        let lastError;
        let transporter;

        for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
            try {
                if (!transporter) {
                    transporter = await this.createTransport();
                }

                const result = await transporter.sendMail(mailOptions);
                console.log(`Email sent successfully on attempt ${attempt}`);
                return result;
            } catch (error) {
                lastError = error;
                console.error(`Attempt ${attempt} failed:`, error.message);

                if (this.isRetryableError(error)) {
                    await this.wait(this.retryDelay * attempt);
                    transporter = null; // Force new connection
                } else {
                    throw error; // Non-retryable error
                }
            }
        }

        throw new Error(`Failed after ${this.maxRetries} attempts. Last error: ${lastError.message}`);
    }

    isRetryableError(error) {
        const retryableCodes = [
            'ECONNRESET',
            'ECONNREFUSED',
            'ETIMEDOUT',
            'ESOCKET'
        ];
        return retryableCodes.includes(error.code);
    }

    wait(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
}

Advanced SMTP Testing Patterns

1. Testing Different Authentication Methods


class SMTPAuthTester {
    constructor(host, port) {
        this.host = host;
        this.port = port;
    }

    async testPlainAuth(username, password) {
        const transport = nodemailer.createTransport({
            host: this.host,
            port: this.port,
            auth: {
                type: 'plain',
                user: username,
                pass: password
            }
        });
        return await transport.verify();
    }

    async testLoginAuth(username, password) {
        const transport = nodemailer.createTransport({
            host: this.host,
            port: this.port,
            auth: {
                type: 'login',
                user: username,
                pass: password
            }
        });
        return await transport.verify();
    }

    async testOAuth2(clientId, clientSecret, refreshToken) {
        const transport = nodemailer.createTransport({
            host: this.host,
            port: this.port,
            auth: {
                type: 'OAuth2',
                user: '[email protected]',
                clientId: clientId,
                clientSecret: clientSecret,
                refreshToken: refreshToken
            }
        });
        return await transport.verify();
    }
}

2. SMTP Security Testing


class SMTPSecurityTester {
    constructor(host, port) {
        this.host = host;
        this.port = port;
    }

    async testTLSSupport() {
        const results = {
            tlsv1: false,
            tlsv11: false,
            tlsv12: false,
            tlsv13: false
        };

        for (const [version, enabled] of Object.entries(results)) {
            try {
                const transport = nodemailer.createTransport({
                    host: this.host,
                    port: this.port,
                    secure: true,
                    tls: {
                        minVersion: version,
                        maxVersion: version
                    }
                });
                await transport.verify();
                results[version] = true;
            } catch (error) {
                console.log(`${version} not supported:`, error.message);
            }
        }

        return results;
    }

    async testCertificate() {
        try {
            const transport = nodemailer.createTransport({
                host: this.host,
                port: this.port,
                secure: true,
                tls: {
                    rejectUnauthorized: true
                }
            });
            await transport.verify();
            return {
                valid: true,
                message: 'Certificate is valid'
            };
        } catch (error) {
            return {
                valid: false,
                message: error.message
            };
        }
    }

    async testSPF() {
        // Implement SPF record verification
        const spf = require('spf-check');
        return await spf.check({
            ip: '192.0.2.0',
            domain: 'example.com',
            sender: '[email protected]'
        });
    }

    async testDKIM() {
        // Implement DKIM signature verification
        const dkim = require('dkim-verify');
        return await dkim.verify(emailContent);
    }
}

3. Performance Testing


class SMTPPerformanceTester {
    constructor(config) {
        this.config = config;
        this.client = new SMTPClient(config);
    }

    async testBulkSending(count, concurrency) {
        const startTime = Date.now();
        const results = {
            total: count,
            successful: 0,
            failed: 0,
            avgLatency: 0
        };

        const batches = this.chunk(Array(count).fill(null), concurrency);
        const latencies = [];

        for (const batch of batches) {
            const promises = batch.map(async () => {
                const start = Date.now();
                try {
                    await this.client.sendWithRetry({
                        from: '[email protected]',
                        to: '[email protected]',
                        subject: 'Performance Test',
                        text: 'Performance test email'
                    });
                    results.successful++;
                    latencies.push(Date.now() - start);
                } catch (error) {
                    results.failed++;
                    console.error('Send failed:', error);
                }
            });

            await Promise.all(promises);
        }

        results.avgLatency = latencies.reduce((a, b) => a + b, 0) / latencies.length;
        results.duration = Date.now() - startTime;
        results.ratePerSecond = count / (results.duration / 1000);

        return results;
    }

    chunk(array, size) {
        const chunks = [];
        for (let i = 0; i < array.length; i += size) {
            chunks.push(array.slice(i, i + size));
        }
        return chunks;
    }
}

Troubleshooting Guide

1. Common SMTP Issues


class SMTPTroubleshooter {
    constructor(host, port) {
        this.host = host;
        this.port = port;
    }

    async diagnose() {
        const results = {
            connectivity: await this.checkConnectivity(),
            authentication: await this.checkAuthentication(),
            tls: await this.checkTLS(),
            dns: await this.checkDNS(),
            blacklists: await this.checkBlacklists()
        };

        return this.generateReport(results);
    }

    async checkConnectivity() {
        try {
            const socket = new require('net').Socket();
            await new Promise((resolve, reject) => {
                socket.connect(this.port, this.host, resolve);
                socket.on('error', reject);
            });
            socket.end();
            return { status: 'success', message: 'Port is open and accepting connections' };
        } catch (error) {
            return { status: 'error', message: `Connection failed: ${error.message}` };
        }
    }

    async checkAuthentication() {
        // Implementation details
    }

    async checkTLS() {
        // Implementation details
    }

    async checkDNS() {
        // Implementation details
    }

    async checkBlacklists() {
        // Implementation details
    }

    generateReport(results) {
        return {
            timestamp: new Date(),
            results,
            recommendations: this.generateRecommendations(results)
        };
    }
}

2. Monitoring and Alerts


class SMTPMonitor {
    constructor(config) {
        this.config = config;
        this.alerts = new Set();
        this.metrics = new Map();
    }

    async startMonitoring() {
        setInterval(() => this.checkHealth(), this.config.interval);
    }

    async checkHealth() {
        const health = await this.performHealthCheck();
        this.updateMetrics(health);
        this.evaluateAlerts(health);
    }

    async performHealthCheck() {
        const client = new SMTPClient(this.config);
        const start = Date.now();

        try {
            await client.sendWithRetry({
                from: this.config.testFrom,
                to: this.config.testTo,
                subject: 'Health Check',
                text: 'SMTP Health Check'
            });

            return {
                status: 'healthy',
                latency: Date.now() - start,
                timestamp: new Date()
            };
        } catch (error) {
            return {
                status: 'unhealthy',
                error: error.message,
                timestamp: new Date()
            };
        }
    }

    updateMetrics(health) {
        this.metrics.set('lastCheck', health);
        this.metrics.set('uptime', this.calculateUptime());
    }

    evaluateAlerts(health) {
        if (health.status === 'unhealthy') {
            this.triggerAlert({
                severity: 'high',
                message: `SMTP server unhealthy: ${health.error}`,
                timestamp: health.timestamp
            });
        }
    }

    triggerAlert(alert) {
        this.alerts.add(alert);
        // Implement alert notification (e.g., email, Slack, etc.)
    }
}

Best Practices and Guidelines

1. Security Considerations

  • Always use TLS for secure connections
  • Implement proper authentication mechanisms
  • Regularly rotate credentials
  • Monitor for suspicious activity
  • Keep SMTP server software updated

2. Performance Optimization

  • Implement connection pooling
  • Use appropriate timeout values
  • Monitor server resources
  • Implement rate limiting
  • Regular performance testing

3. Testing Strategy

  • Maintain separate testing environments
  • Use realistic test data
  • Implement comprehensive error handling
  • Regular security audits
  • Automated testing pipelines

Start SMTP Testing

Begin testing your email infrastructure with Mail7's reliable SMTP testing platform.