feat: year filter, auto-create folders on move, fix MIME parser issues

- Increase limit from 200 to 2000 for bulk operations
- Add year query parameter for filtering messages by year
- Disable BodyStructure fetch (causes parser errors on malformed MIME)
- Auto-create destination folder on TRYCREATE error during move
- Better error handling for move operations
This commit is contained in:
Johan Jongsma 2026-02-01 12:26:44 +00:00
parent 1284a4a390
commit 3690c1c199
2 changed files with 42 additions and 9 deletions

View File

@ -11,6 +11,14 @@ accounts:
tls: starttls
watch:
- INBOX
johan:
host: 127.0.0.1
port: 1143
username: johan@jongsma.me
password: ${JOHAN_BRIDGE_PASSWORD}
tls: starttls
watch:
- INBOX
webhook:
enabled: true

43
main.go
View File

@ -506,8 +506,8 @@ func handleListMessages(w http.ResponseWriter, r *http.Request, client *imapclie
limit := 50
if l := r.URL.Query().Get("limit"); l != "" {
fmt.Sscanf(l, "%d", &limit)
if limit > 200 {
limit = 200
if limit > 2000 {
limit = 2000
}
}
@ -517,11 +517,15 @@ func handleListMessages(w http.ResponseWriter, r *http.Request, client *imapclie
return
}
// Use SEARCH to find messages by date
// Search for messages from the last 90 days to get recent ones
since := time.Now().AddDate(0, 0, -90)
searchCriteria := &imap.SearchCriteria{
Since: since,
// Build search criteria - support year filter for bulk operations
searchCriteria := &imap.SearchCriteria{}
if year := r.URL.Query().Get("year"); year != "" {
var y int
fmt.Sscanf(year, "%d", &y)
if y >= 2000 && y <= 2100 {
searchCriteria.Since = time.Date(y, 1, 1, 0, 0, 0, 0, time.UTC)
searchCriteria.Before = time.Date(y+1, 1, 1, 0, 0, 0, 0, time.UTC)
}
}
searchCmd := client.Search(searchCriteria, nil)
@ -569,7 +573,8 @@ func fetchMessages(client *imapclient.Client, seqSet imap.SeqSet, folder string,
Envelope: true,
Flags: true,
UID: true,
BodyStructure: &imap.FetchItemBodyStructure{},
// BodyStructure disabled - causes parser errors on malformed MIME
// BodyStructure: &imap.FetchItemBodyStructure{},
}
if withBody {
@ -800,7 +805,27 @@ func handleUpdateMessage(w http.ResponseWriter, r *http.Request, client *imapcli
}
if update.MoveTo != nil {
client.Move(uidSet, *update.MoveTo).Wait()
// Try move first
moveCmd := client.Move(uidSet, *update.MoveTo)
if _, err := moveCmd.Wait(); err != nil {
// If folder doesn't exist, create it and retry
if strings.Contains(err.Error(), "TRYCREATE") || strings.Contains(err.Error(), "no such mailbox") {
createCmd := client.Create(*update.MoveTo, nil)
if cerr := createCmd.Wait(); cerr != nil {
http.Error(w, fmt.Sprintf("Create folder failed: %v", cerr), http.StatusInternalServerError)
return
}
// Retry move
moveCmd2 := client.Move(uidSet, *update.MoveTo)
if _, err2 := moveCmd2.Wait(); err2 != nil {
http.Error(w, fmt.Sprintf("Move failed after create: %v", err2), http.StatusInternalServerError)
return
}
} else {
http.Error(w, fmt.Sprintf("Move failed: %v", err), http.StatusInternalServerError)
return
}
}
}
w.Header().Set("Content-Type", "application/json")