Fix IMAP port, add tests, and verify functionality

Co-authored-by: setoelkahfi <1797197+setoelkahfi@users.noreply.github.com>

copilot-swe-agent[bot] committed Oct 13, 2025 at 16:12 UTC 80141e00a3402bb26eda92d204c168c0c24220a9
3 files changed +70 -4
README.md
+3 -3
@@ -31,7 +31,7 @@ A basic SMTP and IMAP server implementation in Rust with TLS/STARTTLS support.
31 cargo run
32 ```
33
34 -The SMTP server listens on `127.0.0.1:2525` and the IMAP server listens on `127.0.0.1:143` by default.
34 +The SMTP server listens on `127.0.0.1:2525` and the IMAP server listens on `127.0.0.1:1143` by default.
35
36 ## Testing
37
@@ -49,10 +49,10 @@ You can test the IMAP server using `nc` (netcat) or `telnet`:
49
50 ```bash
51 # Connect and login
52 -echo -e "a1 CAPABILITY\r\na2 LOGIN user pass\r\na3 LIST \"\" \"*\"\r\na4 SELECT INBOX\r\na5 LOGOUT\r\n" | nc localhost 143
52 +echo -e "a1 CAPABILITY\r\na2 LOGIN user pass\r\na3 LIST \"\" \"*\"\r\na4 SELECT INBOX\r\na5 LOGOUT\r\n" | nc localhost 1143
53
54 # Fetch messages
55 -echo -e "a1 LOGIN user pass\r\na2 SELECT INBOX\r\na3 FETCH 1 (FLAGS BODY[])\r\na4 LOGOUT\r\n" | nc localhost 143
55 +echo -e "a1 LOGIN user pass\r\na2 SELECT INBOX\r\na3 FETCH 1 (FLAGS BODY[])\r\na4 LOGOUT\r\n" | nc localhost 1143
56 ```
57
58 ## Supported Commands
src/imap/listen.rs
+1 -1
@@ -5,7 +5,7 @@ use std::sync::Arc;
5 use tokio::net::{TcpListener, TcpStream};
6
7 pub async fn listen(store: Arc<MailboxStore>) -> anyhow::Result<()> {
8 - let addr = SocketAddr::from(([127, 0, 0, 1], 143));
8 + let addr = SocketAddr::from(([127, 0, 0, 1], 1143));
9 let listener = TcpListener::bind(addr).await?;
10
11 tracing::info!("IMAP server listening on {}", addr);
src/storage.rs
+66
@@ -27,3 +27,69 @@ impl Default for MessageStorage {
27 Self::new()
28 }
29 }
30 +
31 +#[cfg(test)]
32 +mod tests {
33 + use super::*;
34 +
35 + #[test]
36 + fn test_message_storage() {
37 + let storage = MessageStorage::new();
38 +
39 + // Store a message
40 + let from = "sender@example.com".to_string();
41 + let to = vec!["recipient@example.com".to_string()];
42 + let content = "Subject: Test\r\n\r\nTest body".to_string();
43 +
44 + storage.store_message(from.clone(), to.clone(), content.clone());
45 +
46 + // Verify message was stored
47 + if let Some(inbox) = storage.mailbox_store.get_mailbox("INBOX") {
48 + let messages = inbox.get_messages();
49 + assert_eq!(messages.len(), 1);
50 + assert_eq!(messages[0].from, from);
51 + assert_eq!(messages[0].to, to);
52 + assert_eq!(messages[0].subject, "Test");
53 + } else {
54 + panic!("INBOX mailbox not found");
55 + }
56 + }
57 +
58 + #[test]
59 + fn test_multiple_messages() {
60 + let storage = MessageStorage::new();
61 +
62 + // Store multiple messages
63 + storage.store_message(
64 + "sender1@example.com".to_string(),
65 + vec!["recipient@example.com".to_string()],
66 + "Subject: First\r\n\r\nFirst message".to_string()
67 + );
68 +
69 + storage.store_message(
70 + "sender2@example.com".to_string(),
71 + vec!["recipient@example.com".to_string()],
72 + "Subject: Second\r\n\r\nSecond message".to_string()
73 + );
74 +
75 + // Verify both messages were stored
76 + if let Some(inbox) = storage.mailbox_store.get_mailbox("INBOX") {
77 + let messages = inbox.get_messages();
78 + assert_eq!(messages.len(), 2);
79 + assert_eq!(messages[0].subject, "First");
80 + assert_eq!(messages[1].subject, "Second");
81 + }
82 + }
83 +
84 + #[test]
85 + fn test_mailbox_list() {
86 + let storage = MessageStorage::new();
87 + let mailboxes = storage.mailbox_store.list_mailboxes();
88 +
89 + // Verify default mailboxes exist
90 + assert!(mailboxes.contains(&"INBOX".to_string()));
91 + assert!(mailboxes.contains(&"Sent".to_string()));
92 + assert!(mailboxes.contains(&"Drafts".to_string()));
93 + assert!(mailboxes.contains(&"Trash".to_string()));
94 + }
95 +}