1 # POP3 Protocol Documentation
2
3 This document provides comprehensive information about the POP3 (Post Office Protocol version 3) implementation, including setup, usage, testing, and integration with other mail protocols.
4
5 ## Table of Contents
6
7 1. [Overview](#overview)
8 2. [POP3 Protocol Basics](#pop3-protocol-basics)
9 3. [Setup and Configuration](#setup-and-configuration)
10 4. [Usage Examples](#usage-examples)
11 5. [Testing](#testing)
12 6. [Integration with SMTP and IMAP](#integration-with-smtp-and-imap)
13 7. [Troubleshooting](#troubleshooting)
14 8. [Best Practices](#best-practices)
15
16 ## Overview
17
18 POP3 (Post Office Protocol version 3) is an Internet standard protocol used by email clients to retrieve emails from a mail server. It operates on TCP port 110 (or 995 for POP3S with SSL/TLS).
19
20 ### Key Features
21
22 - Simple authentication mechanism (USER/PASS)
23 - Message retrieval and deletion
24 - Mailbox statistics and listing
25 - Minimal server-side state
26 - Optional TLS/SSL support (POP3S)
27
28 ### POP3 vs IMAP
29
30 | Feature | POP3 | IMAP |
31 |---------|------|------|
32 | **Purpose** | Download and delete | Access and manage |
33 | **Messages** | Downloaded to client | Stored on server |
34 | **Folders** | No folder support | Multiple folders |
35 | **Offline Access** | Yes (after download) | Limited |
36 | **Multiple Clients** | Not ideal | Well supported |
37 | **Server Storage** | Minimal after download | Persistent |
38
39 ## POP3 Protocol Basics
40
41 ### Connection States
42
43 A POP3 session goes through three states:
44
45 1. **AUTHORIZATION** - Client authenticates with the server
46 2. **TRANSACTION** - Client retrieves and manages messages
47 3. **UPDATE** - Server commits changes (deletions) and closes connection
48
49 ### Standard Commands
50
51 #### Authorization State Commands
52
53 | Command | Description | Example |
54 |---------|-------------|---------|
55 | `USER` | Specify username | `USER john@example.com` |
56 | `PASS` | Specify password | `PASS secretpassword` |
57 | `QUIT` | Close connection | `QUIT` |
58
59 #### Transaction State Commands
60
61 | Command | Description | Example |
62 |---------|-------------|---------|
63 | `STAT` | Get mailbox statistics | `STAT` |
64 | `LIST` | List messages | `LIST` or `LIST 1` |
65 | `RETR` | Retrieve message | `RETR 1` |
66 | `DELE` | Mark message for deletion | `DELE 1` |
67 | `NOOP` | No operation (keepalive) | `NOOP` |
68 | `RSET` | Unmark deleted messages | `RSET` |
69 | `TOP` | Get message headers | `TOP 1 10` |
70 | `UIDL` | Get unique message ID | `UIDL` or `UIDL 1` |
71 | `QUIT` | Close and commit | `QUIT` |
72
73 ### Response Format
74
75 POP3 uses two types of responses:
76
77 - **Positive**: `+OK` followed by optional information
78 - **Negative**: `-ERR` followed by error message
79
80 Multi-line responses end with a line containing only `.` (period).
81
82 ### Example Session
83
84 ```
85 S: +OK POP3 server ready
86 C: USER testuser
87 S: +OK User accepted
88 C: PASS testpass
89 S: +OK Pass accepted
90 C: STAT
91 S: +OK 2 320
92 C: LIST
93 S: +OK 2 messages (320 octets)
94 S: 1 120
95 S: 2 200
96 S: .
97 C: RETR 1
98 S: +OK 120 octets
99 S: [message content]
100 S: .
101 C: DELE 1
102 S: +OK message 1 deleted
103 C: QUIT
104 S: +OK POP3 server signing off
105 ```
106
107 ## Setup and Configuration
108
109 ### Basic Server Configuration
110
111 ```rust
112 // Example POP3 server configuration structure
113 pub struct Pop3Config {
114 /// Listening address
115 pub host: String,
116
117 /// Listening port (default: 110)
118 pub port: u16,
119
120 /// Enable TLS/SSL (POP3S on port 995)
121 pub enable_tls: bool,
122
123 /// Path to TLS certificate (if TLS enabled)
124 pub tls_cert_path: Option<String>,
125
126 /// Path to TLS private key (if TLS enabled)
127 pub tls_key_path: Option<String>,
128
129 /// Maximum message size (bytes)
130 pub max_message_size: usize,
131
132 /// Session timeout (seconds)
133 pub timeout: u64,
134
135 /// Authentication backend
136 pub auth_backend: AuthBackend,
137
138 /// Message storage backend
139 pub storage_backend: StorageBackend,
140 }
141
142 impl Default for Pop3Config {
143 fn default() -> Self {
144 Pop3Config {
145 host: "127.0.0.1".to_string(),
146 port: 110,
147 enable_tls: false,
148 tls_cert_path: None,
149 tls_key_path: None,
150 max_message_size: 10 * 1024 * 1024, // 10MB
151 timeout: 600, // 10 minutes
152 auth_backend: AuthBackend::File,
153 storage_backend: StorageBackend::Maildir,
154 }
155 }
156 }
157 ```
158
159 ### Starting the Server
160
161 ```rust
162 use smbcloud_mail::pop3::Pop3Server;
163 use smbcloud_mail::pop3::Pop3Config;
164
165 #[tokio::main]
166 async fn main() -> Result<(), Box<dyn std::error::Error>> {
167 // Initialize logging
168 tracing_subscriber::fmt::init();
169
170 // Create configuration
171 let config = Pop3Config {
172 host: "127.0.0.1".to_string(),
173 port: 110,
174 enable_tls: false,
175 ..Default::default()
176 };
177
178 // Create and start server
179 let server = Pop3Server::new(config);
180 server.listen().await?;
181
182 Ok(())
183 }
184 ```
185
186 ### Configuration File Example
187
188 Create a `pop3.toml` configuration file:
189
190 ```toml
191 [server]
192 host = "127.0.0.1"
193 port = 110
194 timeout = 600
195
196 [tls]
197 enabled = false
198 cert_path = "/path/to/cert.pem"
199 key_path = "/path/to/key.pem"
200
201 [limits]
202 max_message_size = 10485760 # 10MB in bytes
203 max_connections = 100
204
205 [authentication]
206 backend = "file"
207 users_file = "/etc/pop3/users.txt"
208
209 [storage]
210 backend = "maildir"
211 maildir_path = "/var/mail"
212 ```
213
214 ## Usage Examples
215
216 ### Using the Rust Client Example
217
218 ```bash
219 # Run the POP3 client example
220 cargo run --example pop3_client
221 ```
222
223 ### Using Python
224
225 ```bash
226 # Run the Python POP3 client
227 python3 docs/scripts/pop3-client.py
228 ```
229
230 ### Using netcat (nc) for Testing
231
232 ```bash
233 # Connect to POP3 server
234 nc localhost 110
235
236 # Then type commands:
237 USER testuser
238 PASS testpass
239 STAT
240 LIST
241 RETR 1
242 QUIT
243 ```
244
245 ### Using telnet
246
247 ```bash
248 telnet localhost 110
249 ```
250
251 Then issue POP3 commands manually.
252
253 ### Using mail clients
254
255 Configure your email client with:
256 - **Server**: localhost (or your server address)
257 - **Port**: 110 (or 995 for POP3S)
258 - **Username**: Your username
259 - **Password**: Your password
260 - **Security**: None (or SSL/TLS for POP3S)
261
262 ## Testing
263
264 ### Unit Tests
265
266 Example unit tests for POP3 functionality:
267
268 ```rust
269 #[cfg(test)]
270 mod tests {
271 use super::*;
272
273 #[tokio::test]
274 async fn test_pop3_connect() {
275 let config = Pop3Config::default();
276 let server = Pop3Server::new(config);
277 // Test server initialization
278 assert!(server.is_ok());
279 }
280
281 #[tokio::test]
282 async fn test_pop3_authentication() {
283 let mut client = Pop3Client::connect("localhost", 110).await.unwrap();
284 let result = client.authenticate("testuser", "testpass").await;
285 assert!(result.is_ok());
286 }
287
288 #[tokio::test]
289 async fn test_pop3_stat() {
290 let mut client = Pop3Client::connect("localhost", 110).await.unwrap();
291 client.authenticate("testuser", "testpass").await.unwrap();
292 let (count, size) = client.stat().await.unwrap();
293 assert!(count >= 0);
294 assert!(size >= 0);
295 }
296
297 #[tokio::test]
298 async fn test_pop3_list() {
299 let mut client = Pop3Client::connect("localhost", 110).await.unwrap();
300 client.authenticate("testuser", "testpass").await.unwrap();
301 let messages = client.list().await.unwrap();
302 assert!(messages.is_ok());
303 }
304
305 #[tokio::test]
306 async fn test_pop3_retrieve() {
307 let mut client = Pop3Client::connect("localhost", 110).await.unwrap();
308 client.authenticate("testuser", "testpass").await.unwrap();
309
310 let (count, _) = client.stat().await.unwrap();
311 if count > 0 {
312 let message = client.retrieve(1).await.unwrap();
313 assert!(!message.is_empty());
314 }
315 }
316
317 #[tokio::test]
318 async fn test_pop3_delete() {
319 let mut client = Pop3Client::connect("localhost", 110).await.unwrap();
320 client.authenticate("testuser", "testpass").await.unwrap();
321
322 let (count, _) = client.stat().await.unwrap();
323 if count > 0 {
324 let result = client.delete(1).await;
325 assert!(result.is_ok());
326
327 // Reset to unmark
328 client.reset().await.unwrap();
329 }
330 }
331
332 #[tokio::test]
333 async fn test_pop3_invalid_credentials() {
334 let mut client = Pop3Client::connect("localhost", 110).await.unwrap();
335 let result = client.authenticate("invalid", "invalid").await;
336 assert!(result.is_err());
337 }
338 }
339 ```
340
341 ### Integration Tests
342
343 ```rust
344 #[cfg(test)]
345 mod integration_tests {
346 use super::*;
347 use tokio::time::{sleep, Duration};
348
349 #[tokio::test]
350 async fn test_complete_pop3_session() {
351 // Start POP3 server
352 let config = Pop3Config::default();
353 let server = Pop3Server::new(config);
354
355 tokio::spawn(async move {
356 server.listen().await.unwrap();
357 });
358
359 // Wait for server to start
360 sleep(Duration::from_millis(100)).await;
361
362 // Connect client
363 let mut client = Pop3Client::connect("localhost", 110).await.unwrap();
364
365 // Authenticate
366 client.authenticate("testuser", "testpass").await.unwrap();
367
368 // Get statistics
369 let (count, size) = client.stat().await.unwrap();
370 assert!(count >= 0);
371
372 // List messages
373 let messages = client.list().await.unwrap();
374 assert_eq!(messages.len(), count);
375
376 // Close
377 client.quit().await.unwrap();
378 }
379
380 #[tokio::test]
381 async fn test_smtp_to_pop3_integration() {
382 // Send email via SMTP
383 let smtp_client = SmtpClient::connect("localhost", 2525).await.unwrap();
384 smtp_client.send_email(
385 "sender@example.com",
386 "recipient@example.com",
387 "Test Subject",
388 "Test Body"
389 ).await.unwrap();
390
391 // Wait for delivery
392 sleep(Duration::from_millis(100)).await;
393
394 // Retrieve via POP3
395 let mut pop3_client = Pop3Client::connect("localhost", 110).await.unwrap();
396 pop3_client.authenticate("recipient@example.com", "password").await.unwrap();
397
398 let (count, _) = pop3_client.stat().await.unwrap();
399 assert!(count > 0);
400
401 let message = pop3_client.retrieve(count).await.unwrap();
402 assert!(message.contains("Test Subject"));
403 assert!(message.contains("Test Body"));
404 }
405 }
406 ```
407
408 ### Mock Testing
409
410 ```rust
411 use mockall::predicate::*;
412 use mockall::*;
413
414 #[automock]
415 pub trait Pop3Storage {
416 fn get_message(&self, user: &str, msg_id: usize) -> Result<String, Error>;
417 fn list_messages(&self, user: &str) -> Result<Vec<(usize, usize)>, Error>;
418 fn delete_message(&self, user: &str, msg_id: usize) -> Result<(), Error>;
419 }
420
421 #[cfg(test)]
422 mod mock_tests {
423 use super::*;
424
425 #[test]
426 fn test_with_mock_storage() {
427 let mut mock = MockPop3Storage::new();
428
429 mock.expect_get_message()
430 .with(eq("testuser"), eq(1))
431 .times(1)
432 .returning(|_, _| Ok("From: test@example.com\n\nTest message".to_string()));
433
434 mock.expect_list_messages()
435 .with(eq("testuser"))
436 .times(1)
437 .returning(|_| Ok(vec![(1, 100), (2, 200)]));
438
439 // Test with mock
440 let message = mock.get_message("testuser", 1).unwrap();
441 assert!(message.contains("Test message"));
442
443 let messages = mock.list_messages("testuser").unwrap();
444 assert_eq!(messages.len(), 2);
445 }
446 }
447 ```
448
449 ## Integration with SMTP and IMAP
450
451 ### Shared Architecture
452
453 ```
454 ┌─────────────────────────────────────────────┐
455 │ Mail Server Architecture │
456 ├─────────────────────────────────────────────┤
457 │ │
458 │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
459 │ │ SMTP │ │ POP3 │ │ IMAP │ │
460 │ │ Server │ │ Server │ │ Server │ │
461 │ │ Port 25 │ │ Port 110 │ │ Port 143 │ │
462 │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
463 │ │ │ │ │
464 │ └─────────────┴─────────────┘ │
465 │ │ │
466 │ ┌───────────▼───────────┐ │
467 │ │ Message Storage │ │
468 │ │ (Maildir/mbox/DB) │ │
469 │ └───────────────────────┘ │
470 │ │ │
471 │ ┌───────────▼───────────┐ │
472 │ │ User Authentication │ │
473 │ │ (LDAP/DB/File) │ │
474 │ └───────────────────────┘ │
475 └─────────────────────────────────────────────┘
476 ```
477
478 ### Shared Storage Example
479
480 ```rust
481 pub trait MessageStorage: Send + Sync {
482 /// Store a new message
483 fn store_message(&self, user: &str, message: &[u8]) -> Result<String, Error>;
484
485 /// Get a message by ID
486 fn get_message(&self, user: &str, message_id: &str) -> Result<Vec<u8>, Error>;
487
488 /// List all messages for a user
489 fn list_messages(&self, user: &str) -> Result<Vec<MessageInfo>, Error>;
490
491 /// Delete a message
492 fn delete_message(&self, user: &str, message_id: &str) -> Result<(), Error>;
493
494 /// Mark message as seen (for IMAP)
495 fn mark_seen(&self, user: &str, message_id: &str) -> Result<(), Error>;
496 }
497
498 // Maildir implementation (works for all protocols)
499 pub struct MaildirStorage {
500 base_path: PathBuf,
501 }
502
503 impl MessageStorage for MaildirStorage {
504 fn store_message(&self, user: &str, message: &[u8]) -> Result<String, Error> {
505 let user_dir = self.base_path.join(user).join("new");
506 std::fs::create_dir_all(&user_dir)?;
507
508 let msg_id = format!("{}.{}", SystemTime::now()
509 .duration_since(UNIX_EPOCH)?.as_secs(), uuid::Uuid::new_v4());
510
511 let msg_path = user_dir.join(&msg_id);
512 std::fs::write(msg_path, message)?;
513
514 Ok(msg_id)
515 }
516
517 fn get_message(&self, user: &str, message_id: &str) -> Result<Vec<u8>, Error> {
518 let paths = [
519 self.base_path.join(user).join("new").join(message_id),
520 self.base_path.join(user).join("cur").join(message_id),
521 ];
522
523 for path in &paths {
524 if path.exists() {
525 return Ok(std::fs::read(path)?);
526 }
527 }
528
529 Err(Error::MessageNotFound)
530 }
531
532 // ... other methods
533 }
534 ```
535
536 ### User Management Example
537
538 ```rust
539 pub trait UserAuthenticator: Send + Sync {
540 fn authenticate(&self, username: &str, password: &str) -> Result<bool, Error>;
541 fn user_exists(&self, username: &str) -> Result<bool, Error>;
542 }
543
544 // File-based authentication (simple example)
545 pub struct FileAuthenticator {
546 users_file: PathBuf,
547 }
548
549 impl UserAuthenticator for FileAuthenticator {
550 fn authenticate(&self, username: &str, password: &str) -> Result<bool, Error> {
551 let contents = std::fs::read_to_string(&self.users_file)?;
552
553 for line in contents.lines() {
554 let parts: Vec<&str> = line.split(':').collect();
555 if parts.len() >= 2 && parts[0] == username {
556 // In production, use proper password hashing (bcrypt, argon2, etc.)
557 return Ok(parts[1] == password);
558 }
559 }
560
561 Ok(false)
562 }
563
564 fn user_exists(&self, username: &str) -> Result<bool, Error> {
565 let contents = std::fs::read_to_string(&self.users_file)?;
566 Ok(contents.lines().any(|line| line.starts_with(username)))
567 }
568 }
569 ```
570
571 ### Complete Integration Example
572
573 ```rust
574 use std::sync::Arc;
575
576 pub struct MailServer {
577 smtp_server: SmtpServer,
578 pop3_server: Pop3Server,
579 imap_server: ImapServer,
580 storage: Arc<dyn MessageStorage>,
581 auth: Arc<dyn UserAuthenticator>,
582 }
583
584 impl MailServer {
585 pub fn new(config: MailServerConfig) -> Result<Self, Error> {
586 let storage = Arc::new(MaildirStorage::new(&config.maildir_path)?);
587 let auth = Arc::new(FileAuthenticator::new(&config.users_file)?);
588
589 Ok(MailServer {
590 smtp_server: SmtpServer::new(
591 config.smtp_config,
592 storage.clone(),
593 auth.clone()
594 ),
595 pop3_server: Pop3Server::new(
596 config.pop3_config,
597 storage.clone(),
598 auth.clone()
599 ),
600 imap_server: ImapServer::new(
601 config.imap_config,
602 storage.clone(),
603 auth.clone()
604 ),
605 storage,
606 auth,
607 })
608 }
609
610 pub async fn start(&self) -> Result<(), Error> {
611 // Start all servers concurrently
612 tokio::try_join!(
613 self.smtp_server.listen(),
614 self.pop3_server.listen(),
615 self.imap_server.listen(),
616 )?;
617
618 Ok(())
619 }
620 }
621
622 // Usage
623 #[tokio::main]
624 async fn main() -> Result<(), Box<dyn std::error::Error>> {
625 let config = MailServerConfig::from_file("mail-server.toml")?;
626 let server = MailServer::new(config)?;
627 server.start().await?;
628 Ok(())
629 }
630 ```
631
632 ## Troubleshooting
633
634 ### Common Issues
635
636 #### 1. Connection Refused
637
638 **Problem**: Client cannot connect to server
639
640 **Possible Causes**:
641 - Server not running
642 - Firewall blocking port 110
643 - Wrong host/port configuration
644
645 **Solutions**:
646 ```bash
647 # Check if server is running
648 netstat -an | grep :110
649
650 # Test connection
651 telnet localhost 110
652
653 # Check firewall
654 sudo ufw status
655 sudo ufw allow 110/tcp
656 ```
657
658 #### 2. Authentication Failures
659
660 **Problem**: `USER` or `PASS` commands return `-ERR`
661
662 **Possible Causes**:
663 - Wrong username/password
664 - User doesn't exist
665 - Authentication backend not configured
666
667 **Solutions**:
668 - Verify credentials
669 - Check server logs
670 - Test with known-good credentials
671
672 ```bash
673 # Check server logs
674 tail -f /var/log/pop3/server.log
675
676 # Test authentication
677 echo -e "USER testuser\r\nPASS testpass\r\nQUIT\r\n" | nc localhost 110
678 ```
679
680 #### 3. Messages Not Found
681
682 **Problem**: `RETR` or `DELE` commands fail
683
684 **Possible Causes**:
685 - Invalid message number
686 - Message already deleted
687 - Storage backend issues
688
689 **Solutions**:
690 ```bash
691 # List messages first
692 echo -e "USER testuser\r\nPASS testpass\r\nLIST\r\nQUIT\r\n" | nc localhost 110
693
694 # Check mailbox directory
695 ls -la /var/mail/testuser/new/
696 ls -la /var/mail/testuser/cur/
697 ```
698
699 #### 4. Connection Timeouts
700
701 **Problem**: Connection drops after period of inactivity
702
703 **Possible Causes**:
704 - Server timeout too short
705 - Network issues
706 - Firewall timeout
707
708 **Solutions**:
709 - Increase server timeout setting
710 - Send periodic `NOOP` commands
711 - Adjust firewall settings
712
713 #### 5. TLS/SSL Errors
714
715 **Problem**: POP3S connection fails
716
717 **Possible Causes**:
718 - Invalid certificate
719 - Wrong port (should be 995)
720 - TLS not enabled on server
721
722 **Solutions**:
723 ```bash
724 # Test TLS connection
725 openssl s_client -connect localhost:995
726
727 # Verify certificate
728 openssl x509 -in /path/to/cert.pem -text -noout
729 ```
730
731 ### Debug Mode
732
733 Enable debug logging:
734
735 ```rust
736 use tracing_subscriber;
737
738 fn main() {
739 tracing_subscriber::fmt()
740 .with_max_level(tracing::Level::DEBUG)
741 .init();
742
743 // ... start server
744 }
745 ```
746
747 ### Network Debugging
748
749 ```bash
750 # Capture POP3 traffic
751 sudo tcpdump -i any -A port 110
752
753 # Monitor connections
754 watch -n 1 'netstat -an | grep :110'
755
756 # Check server process
757 ps aux | grep pop3
758 ```
759
760 ## Best Practices
761
762 ### Security
763
764 1. **Use TLS/SSL**: Always use POP3S (port 995) for production
765 2. **Strong Authentication**: Use secure password hashing (bcrypt, argon2)
766 3. **Rate Limiting**: Implement login attempt rate limiting
767 4. **Input Validation**: Validate all client inputs
768 5. **Timeouts**: Set appropriate connection timeouts
769
770 ### Performance
771
772 1. **Connection Pooling**: Reuse database connections
773 2. **Caching**: Cache frequently accessed data
774 3. **Async I/O**: Use async/await for I/O operations
775 4. **Resource Limits**: Set max connections, message sizes
776 5. **Indexing**: Index message storage for fast lookups
777
778 ### Reliability
779
780 1. **Error Handling**: Handle all errors gracefully
781 2. **Logging**: Log all operations for debugging
782 3. **Monitoring**: Monitor server health and metrics
783 4. **Backups**: Regular backup of message storage
784 5. **Testing**: Comprehensive unit and integration tests
785
786 ### Client Development
787
788 1. **Connection Management**: Properly close connections
789 2. **Error Recovery**: Handle and retry failed operations
790 3. **Timeouts**: Set reasonable timeouts
791 4. **Message Handling**: Process messages efficiently
792 5. **State Tracking**: Track message states (seen, deleted)
793
794 ### Example: Secure Production Configuration
795
796 ```toml
797 [server]
798 host = "0.0.0.0"
799 port = 110
800 timeout = 600
801
802 [tls]
803 enabled = true
804 port = 995
805 cert_path = "/etc/ssl/certs/pop3.crt"
806 key_path = "/etc/ssl/private/pop3.key"
807 min_tls_version = "1.2"
808
809 [security]
810 max_auth_attempts = 3
811 auth_timeout = 30
812 rate_limit_per_ip = 10
813
814 [limits]
815 max_message_size = 52428800 # 50MB
816 max_connections = 1000
817 max_messages_per_session = 1000
818
819 [logging]
820 level = "info"
821 file = "/var/log/pop3/server.log"
822 max_size = "100MB"
823 max_age = 30 # days
824
825 [authentication]
826 backend = "database"
827 db_url = "postgresql://user:pass@localhost/maildb"
828
829 [storage]
830 backend = "maildir"
831 maildir_path = "/var/mail"
832 ```
833
834 ## Additional Resources
835
836 - [RFC 1939 - POP3 Protocol](https://tools.ietf.org/html/rfc1939)
837 - [RFC 2595 - POP3 with TLS](https://tools.ietf.org/html/rfc2595)
838 - [RFC 2449 - POP3 Extension Mechanism](https://tools.ietf.org/html/rfc2449)
839
840 ## Support
841
842 For issues, questions, or contributions:
843 - GitHub Issues: [Repository Issues](https://github.com/smbcloudXYZ/smbcloud-mail-smtp/issues)
844 - Documentation: [Project Wiki](https://github.com/smbcloudXYZ/smbcloud-mail-smtp/wiki)