]>
Commit | Line | Data |
---|---|---|
1 | package main | |
2 | ||
3 | import ( | |
4 | "bufio" | |
5 | "crypto/tls" | |
6 | "fmt" | |
7 | "net" | |
8 | "regexp" | |
9 | "strings" | |
10 | ) | |
11 | ||
12 | func main() { | |
13 | // Replace with your server details and credentials | |
14 | server := "mail.fluffbu.de:993" | |
15 | username := "kek@fluffbu.de" | |
16 | password := "" | |
17 | mailbox := "sorter" | |
18 | moveToFolder := "Archive" | |
19 | ||
20 | // Create TLS connection | |
21 | conn, err := tls.Dial("tcp", server, &tls.Config{}) | |
22 | if err != nil { | |
23 | fmt.Println("Error connecting:", err) | |
24 | return | |
25 | } | |
26 | defer conn.Close() | |
27 | ||
28 | reader := bufio.NewReader(conn) | |
29 | ||
30 | // Read server greeting | |
31 | initialResponse(reader) | |
32 | ||
33 | // Login to the server | |
34 | writeAndRead(reader, conn, "a1 LOGIN "+username+" "+password) | |
35 | ||
36 | // Select the mailbox | |
37 | writeAndRead(reader, conn, "a1 SELECT "+mailbox) | |
38 | ||
39 | // Fetch email IDs (UIDs) | |
40 | messageUIDs := fetchMessageIDs(reader, conn) | |
41 | ||
42 | // Move the emails to the target folder | |
43 | moveEmails(reader, conn, messageUIDs, moveToFolder) | |
44 | ||
45 | // Expunge deleted messages and logout | |
46 | writeAndRead(reader, conn, "a1 EXPUNGE + LOGOUT") | |
47 | } | |
48 | ||
49 | // initialResponse handles the server greeting | |
50 | func initialResponse(reader *bufio.Reader) { | |
51 | greetingloop: | |
52 | for { | |
53 | line, err := reader.ReadString('\n') | |
54 | if err != nil { | |
55 | fmt.Println("Error reading greeting:", err) | |
56 | return | |
57 | } | |
58 | fmt.Print("Server Greeting: " + line) | |
59 | ||
60 | // Exit loop when server is ready (usually contains "OK") | |
61 | if strings.Contains(line, "OK") { | |
62 | break greetingloop | |
63 | } | |
64 | } | |
65 | } | |
66 | ||
67 | // fetchMessageIDs fetches the UID of all messages in the mailbox and returns them as a slice of UIDs | |
68 | func fetchMessageIDs(reader *bufio.Reader, conn net.Conn) []string { | |
69 | // Fetch UIDs for all messages (1:*) | |
70 | fmt.Println("Fetching message UIDs:") | |
71 | // writeAndRead(reader, conn, "a1 UID FETCH 1:* (UID)") | |
72 | fmt.Fprintf(conn, "a1 UID FETCH 1:* (UID)"+"\r\n") | |
73 | ||
74 | var uids []string | |
75 | re := regexp.MustCompile(`UID\s+(\d+)`) | |
76 | readingUIDs := false | |
77 | ||
78 | stringread: | |
79 | for { | |
80 | line, err := reader.ReadString('\n') | |
81 | if err != nil { | |
82 | fmt.Println("Error reading:", err) | |
83 | break stringread | |
84 | } | |
85 | ||
86 | // Start reading UIDs when we see the first UID line | |
87 | if strings.Contains(line, "FETCH (UID") { | |
88 | readingUIDs = true | |
89 | } | |
90 | ||
91 | // Parse UID and collect it in the slice | |
92 | if readingUIDs { | |
93 | match := re.FindStringSubmatch(line) | |
94 | if len(match) > 1 { | |
95 | uid := match[1] | |
96 | fmt.Println("Message UID:", uid) | |
97 | uids = append(uids, uid) | |
98 | } | |
99 | } | |
100 | ||
101 | // Stop reading when we get an "OK", "NO", or "BAD" response | |
102 | if strings.HasPrefix(line, "a1 OK") || strings.HasPrefix(line, "NO") || strings.HasPrefix(line, "BAD") { | |
103 | break stringread | |
104 | } | |
105 | } | |
106 | ||
107 | return uids | |
108 | } | |
109 | ||
110 | // moveEmails moves emails with the given UIDs to the target folder and marks them for deletion in the original folder | |
111 | func moveEmails(reader *bufio.Reader, conn net.Conn, uids []string, moveToFolder string) { | |
112 | if len(uids) == 0 { | |
113 | fmt.Println("No messages to move.") | |
114 | return | |
115 | } | |
116 | ||
117 | // Combine UIDs into a single string | |
118 | uidList := strings.Join(uids, ",") | |
119 | ||
120 | // Copy the messages to the target folder | |
121 | fmt.Println("Moving messages to folder:", moveToFolder) | |
122 | writeAndRead(reader, conn, "a1 UID COPY "+uidList+" "+moveToFolder) | |
123 | ||
124 | // Mark the messages as deleted in the original folder | |
125 | writeAndRead(reader, conn, "a1 UID STORE "+uidList+" +FLAGS.SILENT (\\Deleted)") | |
126 | } | |
127 | ||
128 | func writeAndRead(reader *bufio.Reader, conn net.Conn, command string) error { | |
129 | // Write the command to the IMAP server | |
130 | fmt.Println("C: " + command) | |
131 | fmt.Fprintf(conn, command+"\r\n") | |
132 | ||
133 | // Read the response | |
134 | responseloop: | |
135 | for { | |
136 | line, err := reader.ReadString('\n') | |
137 | if err != nil { | |
138 | fmt.Println("Error reading:", err) | |
139 | return err | |
140 | } | |
141 | ||
142 | // Print the server's response line | |
143 | fmt.Print("S: " + line) | |
144 | ||
145 | // Stop reading when we get an "OK", "NO", or "BAD" response | |
146 | if strings.Contains(line, "a1 OK") || strings.Contains(line, "a1 NO") || strings.Contains(line, "BAD") { | |
147 | break responseloop | |
148 | } | |
149 | } | |
150 | ||
151 | return nil | |
152 | } |