first commit

Signed-off-by: Michael <michael.lindman@gmail.com>
This commit is contained in:
Michael 2021-07-02 21:09:38 +01:00
commit 17e92e8557
6 changed files with 198 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
gomail
logs
msgs
config.yaml
go.sum

3
README.md Normal file
View 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
View 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
View 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
View 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(&section)
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
View 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
}