first commit
Signed-off-by: Michael <michael.lindman@gmail.com>
This commit is contained in:
commit
17e92e8557
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
gomail
|
||||
logs
|
||||
msgs
|
||||
config.yaml
|
||||
go.sum
|
3
README.md
Normal file
3
README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Gomail
|
||||
|
||||
Command line application for pulling imap mail messages and saving them as eml files
|
40
config.go
Normal file
40
config.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Config application configuration
|
||||
type Config struct {
|
||||
Addr string `yaml:"addr"`
|
||||
Username string `yaml:"username"`
|
||||
Password string `yaml:"password"`
|
||||
Logger struct {
|
||||
Path string `yaml:"path"`
|
||||
Mode string `yaml:"mode"`
|
||||
Level int `yaml:"level"`
|
||||
}
|
||||
}
|
||||
|
||||
// NewConfig - create new config instance from file path
|
||||
func NewConfig(configFile string) (config *Config) {
|
||||
file, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
log.Fatalf("Error loading yaml config file %v", err)
|
||||
}
|
||||
if err = yaml.Unmarshal(file, &config); err != nil {
|
||||
log.Fatalf("Error Unmarshaling yaml config file %v", err)
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// NewFile create new config instance from file
|
||||
func NewFile(configFile []byte) (config *Config) {
|
||||
if err := yaml.Unmarshal(configFile, &config); err != nil {
|
||||
log.Fatalf("Error Unmarshaling yaml config file %v", err)
|
||||
}
|
||||
return config
|
||||
}
|
9
go.mod
Normal file
9
go.mod
Normal file
@ -0,0 +1,9 @@
|
||||
module git.0cd.xyz/michael/gomail
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
git.0cd.xyz/michael/gtools v0.1.5
|
||||
github.com/emersion/go-imap v1.1.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
98
mail/mail.go
Normal file
98
mail/mail.go
Normal file
@ -0,0 +1,98 @@
|
||||
package mail
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.0cd.xyz/michael/gtools/colour"
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-imap/client"
|
||||
)
|
||||
|
||||
type Mail struct {
|
||||
Client *client.Client
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
SeqNum uint32
|
||||
Subject string
|
||||
To []*imap.Address
|
||||
From []*imap.Address
|
||||
Date time.Time
|
||||
Body imap.Literal
|
||||
}
|
||||
|
||||
type Messages struct {
|
||||
Message []Message
|
||||
}
|
||||
|
||||
func Login(addr, username, password string) (mail *Mail, err error) {
|
||||
colour.Green("Connecting to %s\n", addr)
|
||||
client, err := client.DialTLS(addr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = client.Login(username, password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Println("Logged in as", username)
|
||||
return &Mail{
|
||||
Client: client,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (mail *Mail) GetMessages(mailbox string, msgs int32) (*Messages, error) {
|
||||
var messages Messages
|
||||
mbox, err := mail.Client.Select(mailbox, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if mbox.Messages == 0 {
|
||||
return nil, errors.New("no messages in mailbox")
|
||||
}
|
||||
seqSet := new(imap.SeqSet)
|
||||
seqSet.AddRange(1, mbox.Messages)
|
||||
var section imap.BodySectionName
|
||||
|
||||
imapMessages := make(chan *imap.Message, msgs)
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- mail.Client.Fetch(seqSet, []imap.FetchItem{imap.FetchEnvelope, section.FetchItem()}, imapMessages)
|
||||
}()
|
||||
|
||||
for msg := range imapMessages {
|
||||
body := msg.GetBody(§ion)
|
||||
if body == nil {
|
||||
return nil, errors.New("server didn't returned message body")
|
||||
}
|
||||
message := Message{
|
||||
SeqNum: msg.SeqNum,
|
||||
Subject: msg.Envelope.Subject,
|
||||
To: msg.Envelope.To,
|
||||
From: msg.Envelope.From,
|
||||
Date: msg.Envelope.Date,
|
||||
Body: body,
|
||||
}
|
||||
messages.Message = append(messages.Message, message)
|
||||
}
|
||||
if err := <-done; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &messages, nil
|
||||
}
|
||||
|
||||
func (mail *Mail) WriteMessages(messages *Messages) error {
|
||||
for _, msg := range messages.Message {
|
||||
body, err := ioutil.ReadAll(msg.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile("./msgs/"+strconv.Itoa(int(msg.SeqNum))+"_"+msg.To[0].Address()+".eml", body, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
43
main.go
Normal file
43
main.go
Normal file
@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.0cd.xyz/michael/gomail/mail"
|
||||
"git.0cd.xyz/michael/gtools/logger"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mailbox, msgs := ui()
|
||||
cfg := NewConfig("./config.yaml")
|
||||
logger := logger.New(cfg.Logger.Path, cfg.Logger.Mode, cfg.Logger.Level)
|
||||
|
||||
mail, err := mail.Login(cfg.Addr, cfg.Username, cfg.Password)
|
||||
if err != nil {
|
||||
logger.Error.Fatal(err)
|
||||
}
|
||||
defer mail.Client.Logout()
|
||||
|
||||
messages, err := mail.GetMessages(*mailbox, int32(*msgs))
|
||||
if err != nil {
|
||||
logger.Error.Fatal(err)
|
||||
}
|
||||
if err := mail.WriteMessages(messages); err != nil {
|
||||
logger.Error.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ui() (mailbox *string, msgs *int) {
|
||||
flag.Usage = func() {
|
||||
fmt.Printf("Usage of %s:\n", os.Args[0])
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
mailbox = flag.String("mailbox", "inbox", "mailbox to scan messages")
|
||||
msgs = flag.Int("msgs", 100, "Number of messages to pull")
|
||||
|
||||
flag.Parse()
|
||||
return mailbox, msgs
|
||||
}
|
Loading…
Reference in New Issue
Block a user