Skip to content

Commit

Permalink
parseMail: add support for mbox
Browse files Browse the repository at this point in the history
Add support for reading email from an mbox.
  • Loading branch information
ferdinandyb committed Jan 22, 2025
1 parent ee0ceba commit a8efb70
Show file tree
Hide file tree
Showing 6 changed files with 1,310 additions and 6 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# Description

Generates a ranked addressbook from a maildir (or similar one-mail-per-file)
folder. It can be used in MUA's like [aerc](http://aerc-mail.org) or
[mutt](http://www.mutt.org/) by grepping the list.
Generates a ranked addressbook from your locally available email. It can be
used in MUA's like [aerc](http://aerc-mail.org) or [mutt](http://www.mutt.org/)
by grepping the list.

Why? No need to manually edit an address book, yet the cached ranking is
available extremely fast.

### Features:

- scans all your emails
- support maildir or similar one-email-per-file formats, and mbox
- ranks based on both recency and frequency of addresses
- collects from To, Cc, Bcc, From, Sender and Reply-To fields
- ranks addresses explicitly emailed by you higher
Expand Down Expand Up @@ -63,9 +64,9 @@ Supported flags:
**maildir**

The paths to the folders that will be scanned. No default is set for this.
These actually do NOT need to be maildir format folders, it only assumes that
each file is an email (it will skip any hidden files and anything that is in
a folder called `tmp`).
These actually do NOT need to be maildir format folders, it will try to read
all files as an email or an mbox (it will skip any hidden files and anything
that is in a folder called `tmp` or `.notmuch`).

**outputpath**

Expand Down
10 changes: 10 additions & 0 deletions e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,3 +282,13 @@ func TestE2EListTemplateDisable(t *testing.T) {
})
}
}

func TestE2EMbox(t *testing.T) {
data := walkSources(
[]string{"./testdata/endtoend"},
[]*regexp.Regexp{regexp.MustCompile("[email protected]")},
nil,
)
classeddata := calculateRanks(data, nil, nil)
assert.Contains(t, classeddata[0], "[email protected]")
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (

require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/emersion/go-mbox v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.9 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emersion/go-mbox v1.0.3 h1:Kac75r/EGi6KZAz48HXal9q7EiaXNl+U5HZfyDz0LKM=
github.com/emersion/go-mbox v1.0.3/go.mod h1:Yp9IVuuOYLEuMv4yjgDHvhb5mHOcYH6x92Oas3QqEZI=
github.com/emersion/go-message v0.18.2 h1:rl55SQdjd9oJcIoQNhubD2Acs1E6IzlZISRTK7x/Lpg=
github.com/emersion/go-message v0.18.2/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
Expand Down
29 changes: 29 additions & 0 deletions parseMail.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"errors"
"fmt"
"io"
"mime"
"os"
"path/filepath"
Expand All @@ -11,10 +13,33 @@ import (
"sync"
"unicode/utf8"

"github.com/emersion/go-mbox"
"github.com/emersion/go-message"
_ "github.com/emersion/go-message/charset"
"github.com/emersion/go-message/mail"
)

func mboxParser(path string, headers chan<- *mail.Header) error {
f, err := os.Open(path)
defer f.Close()
if err != nil {
return err
}
mbr := mbox.NewReader(f)
for {
msg, err := mbr.NextMessage()
if errors.Is(err, io.EOF) {
break
} else if err != nil {
return err
}
entity, err := message.Read(msg)
h := &mail.Header{Header: entity.Header}
headers <- h
}
return nil
}

func messageParser(
paths chan string,
headers chan<- *mail.Header,
Expand All @@ -28,6 +53,10 @@ func messageParser(
}
r, err := mail.CreateReader(f)
if err != nil {
mboxerr := mboxParser(path, headers)
if mboxerr == nil {
continue
}
if utf8.ValidString(err.Error()) {
fmt.Fprintln(os.Stderr, path, err)
} else {
Expand Down
Loading

0 comments on commit a8efb70

Please sign in to comment.