173 lines
3.8 KiB
Go
173 lines
3.8 KiB
Go
package mail
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
|
|
"github.com/emersion/go-imap/v2"
|
|
client "github.com/emersion/go-imap/v2/imapclient"
|
|
"github.com/logrusorgru/aurora/v4"
|
|
"github.com/spf13/viper"
|
|
|
|
"git.amok.space/yevhen/resource-scraper/helper/sugar"
|
|
)
|
|
|
|
type EmailService struct {
|
|
User string
|
|
pass string
|
|
Err error
|
|
client *client.Client
|
|
Mailboxes []*imap.SelectData
|
|
Messages []*client.FetchMessageBuffer
|
|
}
|
|
|
|
func (s *EmailService) CheckErr(msg string, err error) bool {
|
|
if err != nil {
|
|
if sugar.IsDev() {
|
|
sugar.LogError(err.Error())
|
|
}
|
|
s.Err = err
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (s *EmailService) success(msg string) {
|
|
if sugar.IsDev() {
|
|
sugar.LogSuccess(msg)
|
|
}
|
|
}
|
|
|
|
func (s *EmailService) Warn(msg string) {
|
|
if sugar.IsDev() {
|
|
sugar.LogWarning(msg)
|
|
}
|
|
}
|
|
|
|
func (s *EmailService) Connect() {
|
|
box := strings.Split(s.User, "@")
|
|
mail := viper.GetStringMapString("mail." + box[1])
|
|
|
|
conn, err := client.DialTLS(mail["dial-tls"], nil)
|
|
if s.CheckErr("DialTLS", err) {
|
|
return
|
|
}
|
|
|
|
s.client = conn
|
|
s.pass = mail[s.User]
|
|
s.success("connected to " + mail["dial-tls"])
|
|
|
|
//defer s.Logout()
|
|
}
|
|
|
|
func (s *EmailService) Login() {
|
|
s.Connect()
|
|
|
|
err := s.client.Login(s.User, s.pass).Wait()
|
|
if s.CheckErr("Login", err) {
|
|
return
|
|
}
|
|
s.success(s.User + " logged")
|
|
}
|
|
|
|
func (s *EmailService) ListMailboxes(mailboxes []string) {
|
|
selectOptions := &imap.SelectOptions{ReadOnly: true}
|
|
|
|
for _, mailbox := range mailboxes {
|
|
mbox, err := s.client.Select(mailbox, selectOptions).Wait()
|
|
if s.CheckErr("Listing mailbox", err) {
|
|
return
|
|
}
|
|
s.Mailboxes = append(s.Mailboxes, mbox)
|
|
}
|
|
|
|
if len(s.Mailboxes) == 0 {
|
|
s.Warn(sugar.SqueezeLine("mailboxes " + strings.Join(mailboxes, ", ") + " not found"))
|
|
}
|
|
}
|
|
|
|
func (s *EmailService) ListMessages(mailboxes []string, criteria *imap.SearchCriteria) {
|
|
for _, mailbox := range mailboxes {
|
|
mbox, err := s.client.Select(mailbox, nil).Wait()
|
|
if s.CheckErr("Listing mailbox", err) {
|
|
continue
|
|
}
|
|
|
|
seqs, err := s.client.UIDSearch(criteria, nil).Wait()
|
|
if s.CheckErr("UIDSearch", err) {
|
|
return
|
|
}
|
|
|
|
seqSet := imap.SeqSet{}
|
|
seqSet.AddRange(1, mbox.NumMessages)
|
|
if len(seqs.AllUIDs()) == 0 {
|
|
s.Warn("no messages found in mailbox: " + mailbox)
|
|
continue
|
|
}
|
|
s.success(fmt.Sprintf("Search complete, found %d messages: %+v", len(seqs.AllUIDs()), mbox.UIDNext))
|
|
|
|
fetchOptions := &imap.FetchOptions{
|
|
Envelope: true,
|
|
Flags: true,
|
|
BodyStructure: &imap.FetchItemBodyStructure{Extended: true},
|
|
BodySection: []*imap.FetchItemBodySection{{Peek: true, Part: []int{2}}},
|
|
}
|
|
|
|
messages, err := s.client.Fetch(seqSet, fetchOptions).Collect()
|
|
if s.CheckErr("Fetch", err) {
|
|
continue
|
|
}
|
|
|
|
s.Messages = messages
|
|
}
|
|
}
|
|
|
|
func (s *EmailService) LogOut() {
|
|
err := s.client.Logout().Wait()
|
|
if !s.CheckErr("failed to logout", err) {
|
|
s.success("logged out successfully")
|
|
}
|
|
}
|
|
|
|
func (s *EmailService) CreateMailbox(mailboxName string) {
|
|
s.client.Create(mailboxName, nil)
|
|
}
|
|
|
|
func (s *EmailService) MailboxesList() {
|
|
listCmd := s.client.List("", "%", &imap.ListOptions{
|
|
ReturnStatus: &imap.StatusOptions{
|
|
NumMessages: true,
|
|
NumUnseen: true,
|
|
},
|
|
})
|
|
|
|
for {
|
|
mbox := listCmd.Next()
|
|
if mbox == nil {
|
|
break
|
|
}
|
|
|
|
fmt.Printf("%+v\n", mbox)
|
|
}
|
|
|
|
if err := listCmd.Close(); err != nil {
|
|
log.Fatalf("LIST command failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func (s *EmailService) MoveMessageToMailbox(msg *client.FetchMessageBuffer, status string) bool {
|
|
movable := imap.SeqSet{}
|
|
movable.AddNum(msg.SeqNum)
|
|
mailbox := viper.GetStringMapString("stb.move-processed-to-mailbox")
|
|
wait, err := s.client.Move(movable, mailbox[status]).Wait()
|
|
if s.CheckErr("Moving to archive", err) {
|
|
return false
|
|
}
|
|
|
|
fmt.Printf("Message %s moved, srcUIDs: %s, dstUIDs: %s\n", aurora.White(msg.Envelope.MessageID), aurora.Yellow(wait.SourceUIDs), aurora.Yellow(wait.DestUIDs))
|
|
|
|
return true
|
|
}
|