# MailHog API Complete Reference ## Base URL ``` http://localhost:8025/api/v1 ``` ## Authentication If authentication is enabled via `-auth-file`, include Basic Auth headers: ```bash curl -u username:password http://localhost:8025/api/v1/messages ``` ## Message Endpoints ### Get All Messages ```bash curl http://localhost:8025/api/v1/messages ``` **Response Format:** ```json { "total": 2, "count": 2, "start": 0, "items": [ { "ID": "1234567890abcdef1234567890abcdef", "From": "sender@example.com", "To": [ { "Address": "recipient@example.com", "Name": "Recipient Name" } ], "Subject": "Test Email", "Date": "2023-01-01T12:00:00Z", "Content": { "Headers": { "Content-Type": ["text/plain; charset=utf-8"], "Subject": ["Test Email"], "From": ["sender@example.com"], "To": ["recipient@example.com"] }, "Body": "This is the email body", "Size": 1024 }, "MIME": { "Parts": [...] }, "Created": "2023-01-01T12:00:00Z" } ] } ``` ### Get Specific Message ```bash curl http://localhost:8025/api/v1/messages/{message-id} ``` **Example:** ```bash curl http://localhost:8025/api/v1/messages/1234567890abcdef1234567890abcdef ``` ### Get Messages with Limits ```bash # Get first 10 messages curl "http://localhost:8025/api/v1/messages?limit=10" # Get messages with offset (pagination) curl "http://localhost:8025/api/v1/messages?start=10&limit=10" # Get recent messages (sorted by creation date) curl "http://localhost:8025/api/v1/messages?start=0&limit=20" ``` ### Delete All Messages ```bash curl -X DELETE http://localhost:8025/api/v1/messages ``` ### Delete Specific Message ```bash curl -X DELETE http://localhost:8025/api/v1/messages/{message-id} ``` ## Search Endpoints ### Search Messages ```bash curl -X POST http://localhost:8025/api/v1/search \ -H "Content-Type: application/json" \ -d '{"query": "search term"}' ``` **Advanced Search Examples:** ```bash # Search by subject curl -X POST http://localhost:8025/api/v1/search \ -H "Content-Type: application/json" \ -d '{"query": "subject:welcome"}' # Search by sender curl -X POST http://localhost:8025/api/v1/search \ -H "Content-Type: application/json" \ -d '{"query": "from:user@example.com"}' # Search by recipient curl -X POST http://localhost:8025/api/v1/search \ -H "Content-Type: application/json" \ -d '{"query": "to:recipient@example.com"}' # Search body content curl -X POST http://localhost:8025/api/v1/search \ -H "Content-Type: application/json" \ -d '{"query": "content:confirmation link"}' ``` **Search Response:** ```json { "total": 1, "count": 1, "start": 0, "items": [...] } ``` ## MIME and Attachment Endpoints ### Get MIME Content ```bash curl http://localhost:8025/api/v1/messages/{message-id}/mime ``` ### Download Attachment ```bash curl http://localhost:8025/api/v1/messages/{message-id}/attachments/{attachment-id} ``` ### List Attachments ```bash curl http://localhost:8025/api/v1/messages/{message-id}/attachments ``` ## Release Endpoints (Outgoing SMTP) ### Release One Message ```bash curl -X POST http://localhost:8025/api/v1/messages/{message-id}/release ``` **With Custom Recipients:** ```bash curl -X POST http://localhost:8025/api/v1/messages/{message-id}/release \ -H "Content-Type: application/json" \ -d '{"recipients": ["alt@example.com"]}' ``` ### Release Multiple Messages ```bash curl -X POST http://localhost:8025/api/v1/messages/release \ -H "Content-Type: application/json" \ -d '{"ids": ["id1", "id2", "id3"]}' ``` ## Status and Health Endpoints ### Get Server Status ```bash curl http://localhost:8025/api/v1/status ``` **Response:** ```json { "messages": 42, "storage": "memory", "version": "v1.0.0" } ``` ### Health Check ```bash curl -f http://localhost:8025/api/v1/health ``` ## Utility Endpoints ### Get Raw Email Source ```bash curl http://localhost:8025/api/v1/messages/{message-id}/raw ``` ### Parse Email Headers ```bash curl http://localhost:8025/api/v1/messages/{message-id}/headers ``` ## WebSockets ### Real-time Message Updates ```javascript const ws = new WebSocket('ws://localhost:8025/api/v1/websocket'); ws.onmessage = function(event) { const data = JSON.parse(event.data); switch(data.action) { case 'messages': console.log('New messages:', data.messages); break; case 'deleted': console.log('Deleted messages:', data.ids); break; case 'released': console.log('Released messages:', data.ids); break; } }; ``` **WebSocket Message Formats:** **New Message Notification:** ```json { "action": "messages", "messages": [ { "ID": "message-id", "From": "sender@example.com", "To": [{"Address": "recipient@example.com"}], "Subject": "Test", "Created": "2023-01-01T12:00:00Z" } ] } ``` **Message Deleted:** ```json { "action": "deleted", "ids": ["message-id"] } ``` **Message Released:** ```json { "action": "released", "ids": ["message-id"] } ``` ## JavaScript Client Examples ### Basic API Client ```javascript class MailHogClient { constructor(baseUrl = 'http://localhost:8025', auth = null) { this.baseUrl = baseUrl; this.auth = auth; } async request(endpoint, options = {}) { const url = `${this.baseUrl}/api/v1${endpoint}`; const config = { headers: { 'Content-Type': 'application/json', ...options.headers }, ...options }; if (this.auth) { config.headers.Authorization = `Basic ${btoa(this.auth)}`; } const response = await fetch(url, config); return response.json(); } async getMessages(limit = 50, start = 0) { return this.request(`/messages?limit=${limit}&start=${start}`); } async getMessage(id) { return this.request(`/messages/${id}`); } async searchMessages(query) { return this.request('/search', { method: 'POST', body: JSON.stringify({ query }) }); } async deleteMessages(ids) { if (ids === 'all') { return this.request('/messages', { method: 'DELETE' }); } return this.request(`/messages/${ids}`, { method: 'DELETE' }); } async releaseMessage(id, recipients = null) { const body = recipients ? { recipients } : undefined; return this.request(`/messages/${id}/release`, { method: 'POST', body: body ? JSON.stringify(body) : undefined }); } } // Usage const client = new MailHogClient(); // Get all messages client.getMessages().then(data => console.log(data.total)); // Search for specific emails client.searchMessages('subject:welcome').then(data => console.log(data.items)); ``` ### WebSocket Integration ```javascript class MailHogWebSocket { constructor(baseUrl = 'ws://localhost:8025') { this.baseUrl = baseUrl; this.callbacks = {}; } connect() { this.ws = new WebSocket(`${this.baseUrl}/api/v1/websocket`); this.ws.onmessage = (event) => { const data = JSON.parse(event.data); if (this.callbacks[data.action]) { this.callbacks[data.action](data); } }; this.ws.onerror = (error) => { console.error('WebSocket error:', error); }; this.ws.onclose = () => { console.log('WebSocket connection closed'); // Auto-reconnect setTimeout(() => this.connect(), 5000); }; } on(action, callback) { this.callbacks[action] = callback; } onNewMessages(callback) { this.on('messages', callback); } onMessagesDeleted(callback) { this.on('deleted', callback); } onMessagesReleased(callback) { this.on('released', callback); } } // Usage const ws = new MailHogWebSocket(); ws.connect(); ws.onNewMessages((data) => { console.log('New messages received:', data.messages); }); ``` ## Python Client Examples ### Requests-based Client ```python import requests import json from typing import List, Dict, Optional class MailHogClient: def __init__(self, base_url: str = "http://localhost:8025", auth: tuple = None): self.base_url = base_url self.auth = auth self.api_url = f"{base_url}/api/v1" def _request(self, endpoint: str, method: str = "GET", data: dict = None) -> dict: url = f"{self.api_url}{endpoint}" response = requests.request( method, url, json=data, auth=self.auth ) response.raise_for_status() return response.json() def get_messages(self, limit: int = 50, start: int = 0) -> dict: return self._request(f"/messages?limit={limit}&start={start}") def get_message(self, message_id: str) -> dict: return self._request(f"/messages/{message_id}") def search_messages(self, query: str) -> dict: return self._request("/search", method="POST", data={"query": query}) def delete_messages(self, message_ids: str = "all") -> dict: if message_ids == "all": return self._request("/messages", method="DELETE") return self._request(f"/messages/{message_ids}", method="DELETE") def release_message(self, message_id: str, recipients: List[str] = None) -> dict: data = {"recipients": recipients} if recipients else None return self._request(f"/messages/{message_id}/release", method="POST", data=data) # Usage client = MailHogClient() # Get all messages messages = client.get_messages() print(f"Total messages: {messages['total']}") # Search for specific emails search_results = client.search_messages("subject:welcome") print(f"Found {search_results['total']} messages") ``` ## Testing Examples ### Integration Test Example ```javascript // Jest/Mocha integration test example describe('Email Functionality', () => { const mailhog = new MailHogClient(); beforeEach(async () => { // Clear all messages before each test await mailhog.deleteMessages('all'); }); afterEach(async () => { // Clean up after each test await mailhog.deleteMessages('all'); }); it('should send welcome email', async () => { // Trigger email sending in your application await sendWelcomeEmail('test@example.com'); // Wait for email to be processed await new Promise(resolve => setTimeout(resolve, 1000)); // Verify email was received const messages = await mailhog.searchMessages('to:test@example.com'); expect(messages.total).toBe(1); const message = messages.items[0]; expect(message.Subject).toContain('Welcome'); expect(message.From).toContain('noreply@yourapp.com'); }); it('should handle bulk email sending', async () => { const recipients = ['user1@test.com', 'user2@test.com', 'user3@test.com']; // Send bulk emails await sendBulkNotifications(recipients); // Wait for processing await new Promise(resolve => setTimeout(resolve, 3000)); // Verify all emails were received const messages = await mailhog.getMessages(); expect(messages.total).toBe(recipients.length); // Verify recipients const recipientAddresses = messages.items.flatMap(msg => msg.To.map(to => to.Address) ); recipients.forEach(recipient => { expect(recipientAddresses).toContain(recipient); }); }); }); ``` ### Load Testing Example ```bash #!/bin/bash # load_test_mailhog.sh BASE_URL="http://localhost:8025" CONCURRENT_REQUESTS=50 TOTAL_REQUESTS=1000 echo "Starting MailHog API load test..." # Create temp file for results RESULT_FILE=$(mktemp) # Run concurrent curl requests for ((i=1; i<=CONCURRENT_REQUESTS; i++)); do { for ((j=1; j<=TOTAL_REQUESTS/CONCURRENT_REQUESTS; j++)); do start_time=$(date +%s%N) curl -s -o /dev/null -w "%{http_code},%{time_total}" \ "$BASE_URL/api/v1/messages" >> "$RESULT_FILE" echo ",$(( ($(date +%s%N) - start_time) / 1000000 ))" >> "$RESULT_FILE" done } & done # Wait for all background processes wait # Analyze results echo "Load test completed. Analyzing results..." awk -F',' ' { status[$1]++ if ($1 == "200") { sum_time += $2 sum_response += $3 count++ } } END { printf "Success Rate: %.2f%%\n", (status["200"]/NR)*100 printf "Average Response Time: %.3f ms\n", sum_time/count*1000 printf "Average Server Response Time: %.3f ms\n", sum_response/count for (code in status) { printf "HTTP %s: %d requests\n", code, status[code] } }' "$RESULT_FILE" rm "$RESULT_FILE" ``` ## Error Handling ### Common HTTP Status Codes - **200 OK**: Request successful - **400 Bad Request**: Invalid request parameters - **401 Unauthorized**: Authentication required - **404 Not Found**: Message or endpoint not found - **500 Internal Server Error**: Server error ### Error Response Format ```json { "error": "Error message description", "code": "ERROR_CODE" } ``` ### Retry Logic Example ```javascript async function robustMailHogRequest(client, endpoint, options = {}) { const maxRetries = 3; const retryDelay = 1000; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { return await client.request(endpoint, options); } catch (error) { if (attempt === maxRetries) { throw error; } if (error.status >= 500 || error.status === 0) { // Retry on server errors or connection issues console.log(`Attempt ${attempt} failed, retrying in ${retryDelay}ms...`); await new Promise(resolve => setTimeout(resolve, retryDelay)); continue; } // Don't retry on client errors throw error; } } } ```