How to use fetch method of imap Package

Best Venom code snippet using imap.fetch

client.go

Source:client.go Github

copy

Full Screen

1package main2// Copyright (c) 2020 - Valentin Kuznetsov <vkuznet AT gmail dot com>3// goimapsync main module, it implements the following actions:4// - "sync" mails from local maildir to IMAP5// - "fetch-new" new mails from IMAP to local maildir folder6// - "fetch-all" all mails from IMAP to local maildir folder7// - "move" mail(s) on IMAP server to given folder and message id8import (9 "bufio"10 "crypto/md5"11 "database/sql"12 "encoding/hex"13 "flag"14 "fmt"15 "io"16 "io/ioutil"17 "log"18 "net/mail"19 "os"20 "runtime"21 "strings"22 "sync"23 "time"24 imap "github.com/emersion/go-imap"25 "github.com/emersion/go-imap/client"26)27// global variable to keep pointer to mdb28var mdb *sql.DB29// version of the code30var gitVersion, gitTag string31// Info function returns version string of the server32func info() string {33 goVersion := runtime.Version()34 tstamp := time.Now().Format("2006-02-01")35 return fmt.Sprintf("gpm git=%s tag=%s go=%s date=%s", gitVersion, gitTag, goVersion, tstamp)36}37// global variables we use across the code38var imapFolders map[string][]string39var hostname string40// Message structure holds all information about emails message41type Message struct {42 Path string // location of the message in local file dir43 MessageId string // message Id44 Flags []string // message Flags45 Imap string // name of imap server it belongs to46 Subject string // message subject47 SeqNumber uint32 // message sequence number48 HashId string // message id md5 hash49}50// String function dumps Message info51func (m *Message) String() string {52 return fmt.Sprintf("<Imap:%s SeqNum:%v HashId:%v Path:%s MessageId:%s Flags:%v Subject: %s>", m.Imap, m.SeqNumber, m.HashId, m.Path, m.MessageId, m.Flags, m.Subject)53}54// ServerClient structure which holds IMAP server alias name and connection pointer55type ServerClient struct {56 Name string // name of IMAP server57 Client *client.Client // connected client to IMAP server58}59// helper function which extracts flags from given email file name60func getFlags(fname string) []string {61 // example of file name in our Inbox62 // <tstamp.id.hostname:2,flags>63 if strings.Contains(fname, ",") {64 arr := strings.Split(fname, ",")65 flags := arr[len(arr)-1]66 return strings.Split(flags, "")67 }68 return []string{}69}70// helper function which extracts message id from given email file71func getMessageId(fname string) string {72 file, err := os.Open(fname)73 if err != nil {74 log.Fatal(err)75 }76 defer file.Close()77 scanner := bufio.NewScanner(file)78 for scanner.Scan() {79 line := scanner.Text()80 if strings.HasPrefix(strings.ToLower(scanner.Text()), "message-id:") {81 arr := strings.Split(line, ":")82 if len(arr) > 0 {83 return strings.Trim(arr[1], " ")84 }85 }86 }87 return ""88}89// helper function to connect to our IMAP servers90func connect() map[string]*client.Client {91 defer timing("connect", time.Now())92 defer profiler("connect")()93 cmap := make(map[string]*client.Client)94 ch := make(chan ServerClient, len(Config.Servers))95 defer close(ch)96 for _, srv := range Config.Servers {97 go func(s Server) {98 var c *client.Client99 var err error100 if s.UseTls {101 c, err = client.DialTLS(s.Uri, nil)102 } else {103 c, err = client.Dial(s.Uri)104 }105 if err != nil {106 log.Fatal(err)107 }108 if err := c.Login(s.Username, s.Password); err != nil {109 log.Fatal(err)110 }111 if Config.Verbose > 0 {112 log.Println("Logged into", s.Uri)113 }114 ch <- ServerClient{Name: s.Name, Client: c}115 }(srv)116 }117 for i := 0; i < len(Config.Servers); i++ {118 s := <-ch119 cmap[s.Name] = s.Client120 }121 return cmap122}123// helper function to logout from all IMAP clients124func logout(cmap map[string]*client.Client) {125 for _, c := range cmap {126 c.Logout()127 }128}129// helper function which takes a snapshot of remote IMAP servers130// and return list of messages131func readImap(c *client.Client, imapName, folder string, newMessages bool) []Message {132 defer timing("readImap", time.Now())133 defer profiler("readImap")()134 // Select given imap folder135 mbox, err := c.Select(folder, false)136 if err != nil {137 log.Printf("Folder '%s' on '%s', error: %v\n", folder, imapName, err)138 return []Message{}139 }140 // get messages141 seqset := new(imap.SeqSet)142 var nmsg uint32143 if newMessages {144 // get only new messages145 criteria := imap.NewSearchCriteria()146 criteria.WithoutFlags = []string{imap.SeenFlag}147 ids, err := c.Search(criteria)148 if err != nil {149 log.Fatal(err)150 }151 if len(ids) > 0 {152 seqset.AddNum(ids...)153 nmsg = uint32(len(ids))154 log.Printf("Found %d new message(s) in folder '%s' on '%s'\n", nmsg, folder, imapName)155 } else {156 log.Printf("No new messages in folder '%s' on '%s'\n", folder, imapName)157 return []Message{}158 }159 } else {160 // get all messages from mailbox161 from := uint32(1)162 to := mbox.Messages163 seqset.AddRange(from, to)164 nmsg = to165 }166 // section will be used only in writeContent167 section := &imap.BodySectionName{}168 messages := make(chan *imap.Message, nmsg)169 items := []imap.FetchItem{section.FetchItem(), imap.FetchFlags, imap.FetchEnvelope}170 // TODO: use goroutine until this issue will be solved171 // https://github.com/emersion/go-imap/issues/382172 done := make(chan error, 1)173 go func() {174 done <- c.Fetch(seqset, items, messages)175 }()176 // err = c.Fetch(seqset, items, messages)177 // if err != nil {178 // log.Fatal(err)179 // }180 seqNum := uint32(1)181 var msgs []Message182 var wg sync.WaitGroup183 for msg := range messages {184 var m Message185 if msg == nil || msg.Envelope == nil {186 continue187 }188 mid := msg.Envelope.MessageId189 sub := msg.Envelope.Subject190 hid := md5hash(mid)191 flags := msg.Flags192 m = Message{MessageId: mid, Flags: flags, Imap: imapName, Subject: sub, SeqNumber: seqNum, HashId: hid}193 if mid == "" || hid == "" {194 log.Printf("read empty mail %s %v out of %v from %s\n", m.String(), seqNum, nmsg, imapName)195 continue196 }197 log.Printf("read %s %v out of %v from %s\n", m.String(), seqNum, nmsg, imapName)198 r := msg.GetBody(section)199 entry, e := findMessage(hid)200 if Config.Verbose > 1 {201 log.Println("hid", hid, "DB entry", entry.String(), e)202 }203 if e == nil && entry.HashId == hid {204 if Config.Verbose > 0 {205 log.Println("Mail with hash", hid, "already exists")206 }207 } else {208 if newMessages {209 m.Flags = append(m.Flags, imap.RecentFlag)210 }211 if !isMailWritten(m) {212 wg.Add(1)213 go writeMail(imapName, folder, m, r, &wg)214 } else {215 // check if mail is presented in our DB, if not we should insert its entry216 msg, e := findMessage(m.HashId)217 if e == nil && msg.HashId == "" {218 m.Path = findPath(m.Imap, m.HashId)219 insertMessage(m)220 }221 }222 }223 msgs = append(msgs, m)224 seqNum += 1225 }226 wg.Wait()227 return msgs228}229// helper function to find message path in local maildir230func findPath(imapName, hid string) string {231 var mdict map[string]string232 if Config.CommonInbox {233 mdict = readMaildir("", "INBOX")234 } else {235 for k, v := range readMaildir(imapName, "INBOX") {236 mdict[k] = v237 }238 }239 if path, ok := mdict[hid]; ok {240 return path241 }242 return ""243}244// helper function to check if mail was previously written in local maildir245func isMailWritten(m Message) bool {246 var mdict map[string]string247 if Config.CommonInbox {248 mdict = readMaildir("", "INBOX")249 } else {250 for k, v := range readMaildir(m.Imap, "INBOX") {251 mdict[k] = v252 }253 }254 for hid := range mdict {255 if hid == m.HashId {256 return true257 }258 }259 return false260}261// helper function to create an md5 hash of given message Id262func md5hash(mid string) string {263 h := md5.New()264 h.Write([]byte(mid))265 return hex.EncodeToString(h.Sum(nil))266}267// helper function to create maildir map of existing mails268func readMaildir(imapName, folder string) map[string]string {269 // when writing to local mail dir the folder name should not cotain slashes270 // replace slash with dot271 folder = strings.Replace(folder, "/", ".", -1)272 // create proper dir structure in maildir area273 var dirs = []string{"cur", "new", "tmp"}274 fdir := localFolder(imapName, folder)275 for _, d := range dirs {276 fpath := fmt.Sprintf("%s/%s/%s", Config.Maildir, fdir, d)277 os.MkdirAll(fpath, os.ModePerm)278 }279 if Config.Verbose > 0 {280 log.Println("Read local mails from", fmt.Sprintf("%s/%s", Config.Maildir, fdir))281 }282 // create mail dict which we'll return upstream283 mdict := make(map[string]string)284 // each file in maildir has format: <tstamp.hid.hostname:2,flags>285 for _, d := range dirs {286 root := fmt.Sprintf("%s/%s/%s", Config.Maildir, fdir, d)287 files, err := ioutil.ReadDir(root)288 if err != nil {289 log.Println("Error reading", root, err)290 continue291 }292 for _, f := range files {293 fname := fmt.Sprintf("%s/%s", root, f.Name())294 arr := strings.Split(fname, ".")295 mdict[arr[1]] = fname296 }297 }298 return mdict299}300// helper to get local maildir folder301func localFolder(imapName, folder string) string {302 if imapName == "" {303 return folder304 } else if strings.ToLower(folder) == "inbox" && Config.CommonInbox {305 return folder306 }307 return fmt.Sprintf("%s/%s", imapName, folder)308}309// helper function to return short flag names310func flagSymbols(flags []string) string {311 var flag string312 for _, f := range flags {313 f = strings.ToLower(strings.Replace(f, "\\", "", -1))314 if f == "seen" {315 f = "S"316 } else if f == "recent" {317 f = "N"318 } else if f == "answered" {319 f = "A"320 } else if f == "junk" {321 f = "J"322 } else {323 continue324 }325 flag = fmt.Sprintf("%s%s", flag, f)326 }327 if flag == "" {328 flag = "S"329 }330 return flag331}332// helper function to write emails in imapName folder of local maildir333func writeMail(imapName, folder string, m Message, r io.Reader, wg *sync.WaitGroup) {334 hid := m.HashId // hash id of the message id335 flags := m.Flags // message flags336 defer timing("writeMail", time.Now())337 defer profiler("writeMail")()338 defer wg.Done()339 // construct file name with the following format:340 // tstamp.hid.hostname:2,flags341 tstamp := time.Now().Unix()342 flag := flagSymbols(flags)343 if Config.Verbose > 0 {344 log.Println("writeMail", tstamp, hid, flags, flag)345 }346 fdir := localFolder(imapName, folder)347 fname := fmt.Sprintf("%d.%s.%s:2,%s", tstamp, hid, hostname, flag)348 fpath := fmt.Sprintf("%s/%s/cur/%s", Config.Maildir, fdir, fname)349 if strings.Contains(flag, "N") {350 fname = fmt.Sprintf("%d.%s.%s", tstamp, hid, hostname)351 fpath = fmt.Sprintf("%s/%s/new/%s", Config.Maildir, fdir, fname)352 }353 // check if our file exist354 if _, err := os.Stat(fpath); err == nil {355 if Config.Verbose > 0 {356 log.Println("File", fpath, "already exists")357 }358 return359 }360 // proceed and create a file with our email361 file, err := os.Create(fpath)362 if err != nil {363 log.Println("unable to open", fpath, err)364 return365 }366 defer file.Close()367 msg, err := mail.ReadMessage(r)368 if err != nil {369 log.Println("Unable to read a message", err)370 return371 }372 // write headers373 for k, v := range msg.Header {374 line := fmt.Sprintf("%s: %s\n", k, strings.Join(v, " "))375 _, e := file.WriteString(line)376 if e != nil {377 log.Printf("unable to write '%s', error: %v\n", line, e)378 return379 }380 }381 // write body382 body, err := ioutil.ReadAll(msg.Body)383 if err == nil {384 _, e := file.Write(body)385 if e != nil {386 log.Println("unable to write msg body, error", e)387 return388 }389 }390 // write message info into DB391 m.Path = fpath392 err = insertMessage(m)393 if err != nil {394 log.Fatal("message was written to file-system but not in DB, error: ", err)395 }396}397// helper function to get list of all imap folders398func getImapFolders(c *client.Client, imapName string) []string {399 // List mailboxes400 mailboxes := make(chan *imap.MailboxInfo, 10)401 done := make(chan error, 1)402 go func() {403 done <- c.List("", "*", mailboxes)404 }()405 var folders []string406 for m := range mailboxes {407 folders = append(folders, m.Name)408 }409 if err := <-done; err != nil {410 log.Fatal(err)411 }412 return folders413}414// helper function to get folder name for given IMAP server415func imapFolder(imapName, folder string) string {416 // if no folder is given, we'll immediately return417 if folder == "" {418 return folder419 }420 folders := imapFolders[imapName]421 for _, f := range folders {422 if strings.ToLower(f) == strings.ToLower(folder) {423 return f424 }425 }426 // defaults427 if strings.ToLower(folder) == "inbox" {428 return "INBOX"429 }430 if strings.ToLower(folder) == "spam" {431 return "Spam"432 }433 // at this point we should through an error434 log.Fatalf("No folder '%s' found in imap '%s' folder list '%v'\n", folder, imapName, folders)435 return ""436}437// MoveMessage moves message in given imap server into specifc folder438func MoveMessage(c *client.Client, imapName string, msg Message, folderName string) {439 defer timing("MoveMessage", time.Now())440 defer profiler("MoveMessage")()441 // inbox folder442 inboxFolder := imapFolder(imapName, "inbox")443 folder := imapFolder(imapName, folderName)444 seqset := new(imap.SeqSet)445 seqset.AddNum(msg.SeqNumber)446 // connect to given Spam folder447 _, err := c.Select(inboxFolder, false)448 if err != nil {449 log.Fatal(err)450 }451 if folder == "" {452 log.Printf("delete %v\n", msg.String())453 } else {454 log.Printf("move %v to '%s' on %s\n", msg.MessageId, folder, imapName)455 }456 // copy mail to folder457 if folder != "" {458 // mark mail as seen in our inbox459 item := imap.FormatFlagsOp(imap.AddFlags, true)460 flags := []interface{}{imap.SeenFlag}461 if err := c.Store(seqset, item, flags, nil); err != nil {462 log.Fatal(err)463 }464 if err := c.Copy(seqset, folder); err != nil {465 log.Fatal(err)466 }467 }468 // mark mail as deleted on IMAP server469 item := imap.FormatFlagsOp(imap.AddFlags, true)470 flags := []interface{}{imap.DeletedFlag}471 if err := c.Store(seqset, item, flags, nil); err != nil {472 log.Fatal(err)473 }474 // then delete it in inbox folder475 if err := c.Expunge(nil); err != nil {476 log.Fatal(err)477 }478}479// Move message on IMAP to a given folder, if folder name is not given the mail480// will be deleted481func Move(c *client.Client, imapName, match, folderName string) {482 if folderName == "" || match == "" {483 log.Fatal("Move operation requires both folder and message id")484 }485 defer timing("Move", time.Now())486 defer profiler("Move")()487 // inbox folder488 inboxFolder := imapFolder(imapName, "inbox")489 folder := imapFolder(imapName, folderName)490 // check if given match is existing file, if so we'll491 // extract from it MatchedId492 if _, err := os.Stat(match); err == nil {493 match = getMessageId(match)494 }495 // Select INBOX496 mbox, err := c.Select(inboxFolder, false)497 if err != nil {498 log.Fatal(err)499 }500 // Get messages from INBOX501 from := uint32(1)502 to := mbox.Messages503 seqset := new(imap.SeqSet)504 seqset.AddRange(from, to)505 if Config.Verbose > 0 {506 log.Println("Fetch from IMAP", imapName, folderName, from, to)507 }508 messages := make(chan *imap.Message, to)509 items := []imap.FetchItem{imap.FetchFlags, imap.FetchUid, imap.FetchEnvelope}510 // TODO: use goroutine until this issue will be solved511 // https://github.com/emersion/go-imap/issues/382512 done := make(chan error, 1)513 go func() {514 done <- c.Fetch(seqset, items, messages)515 }()516 // err = c.Fetch(seqset, items, messages)517 // if err != nil {518 // log.Fatal(err)519 // }520 seqNum := uint32(1)521 for msg := range messages {522 if Config.Verbose > 1 {523 log.Println("* "+msg.Envelope.Subject+" MessageId ", msg.Envelope.MessageId)524 }525 if msg.Envelope.MessageId == match {526 if Config.Verbose > 0 {527 log.Printf("Found match: seq:%v Envelope: %+v Flags: %+v\n", seqNum, msg.Envelope, msg.Flags)528 }529 mid := msg.Envelope.MessageId530 hid := md5hash(mid)531 sub := msg.Envelope.Subject532 flags := msg.Flags533 m := Message{HashId: hid, MessageId: mid, Flags: flags, Imap: imapName, Subject: sub, SeqNumber: seqNum}534 MoveMessage(c, imapName, m, folder)535 return536 }537 seqNum += 1538 }539}540// Fetch content of given folder from IMAP into local maildir541func Fetch(c *client.Client, imapName, folder string, newMessages bool) {542 defer timing("Fetch", time.Now())543 defer profiler("Fetch")()544 log.Printf("Fetch %s from %s\n", folder, imapName)545 for _, m := range readImap(c, imapName, folder, newMessages) {546 if Config.Verbose > 0 {547 log.Println("fetch", m.String())548 }549 }550}551// Sync provides sync between local maildir and IMAP servers552func Sync(cmap map[string]*client.Client, dryRun bool) {553 defer timing("Sync", time.Now())554 defer profiler("Sync")()555 var mlist []Message556 for imapName, c := range cmap {557 // read new messages from IMAP558 newMessages := true559 log.Println("### read new messages on", imapName)560 for _, m := range readImap(c, imapName, "INBOX", newMessages) {561 if Config.Verbose > 0 {562 log.Println("Read new message", m.String())563 }564 }565 // read all messages from IMAP, since we may miss some of them566 // in local maildir if those were read on another device(s)567 // this step will ensure that we get local copies of non-new messages568 log.Println("### read all messages on", imapName)569 newMessages = false570 for _, msg := range readImap(c, imapName, "INBOX", newMessages) {571 mlist = append(mlist, msg)572 }573 }574 // get local maildir snapshot575 log.Println("### read local maildir")576 var mdict map[string]string577 if Config.CommonInbox {578 mdict = readMaildir("", "INBOX")579 } else {580 for name := range cmap {581 for k, v := range readMaildir(name, "INBOX") {582 mdict[k] = v583 }584 }585 }586 // now loop over messages we got from IMAP and compare with our local maildir587 // then we collect message ids for deletion588 var dlist []Message589 for _, msg := range mlist {590 // check if our message exists in DB591 m, e := findMessage(msg.HashId)592 if e == nil && m.HashId == msg.HashId {593 // we found message in DB, check if it exists in local maildir594 if _, ok := mdict[m.HashId]; !ok {595 // message is not found in local maildir and we need to delete it596 if dryRun {597 log.Println("dry-run expunge", msg.String())598 } else {599 dlist = append(dlist, msg)600 }601 }602 }603 }604 if !dryRun {605 removeImapMessages(cmap, dlist)606 }607}608// helper function to remove messages in IMAP server(s)609// it takes list of messages610func removeImapMessages(cmap map[string]*client.Client, mlist []Message) {611 defer timing("removeImapMessages", time.Now())612 defer profiler("removeImapMessages")()613 if Config.Verbose > 0 {614 log.Println("removeImapMessages", mlist)615 }616 for imapName, c := range cmap {617 // select messages from IMAP inbox folder618 inboxFolder := imapFolder(imapName, "inbox")619 _, err := c.Select(inboxFolder, false)620 if err != nil {621 log.Fatal(err)622 }623 // get list of message seq numbers for our IMAP server624 var slist []uint32625 var hlist []string626 for _, m := range mlist {627 if m.Imap == imapName {628 slist = append(slist, m.SeqNumber)629 hlist = append(hlist, m.HashId)630 }631 }632 seqset := new(imap.SeqSet)633 seqset.AddNum(slist...)634 if Config.Verbose > 0 {635 log.Printf("%s, remove seqset: %v\n", imapName, seqset)636 }637 if seqset.Empty() {638 continue639 }640 // now we mark messages for deletion in IMAP641 item := imap.FormatFlagsOp(imap.AddFlags, true)642 flags := []interface{}{imap.DeletedFlag}643 if err := c.Store(seqset, item, flags, nil); err != nil {644 log.Fatal(err)645 }646 // delete messages on IMAP server647 if err := c.Expunge(nil); err != nil {648 log.Fatal(err)649 }650 // delete messages in local maildir DB651 for _, hid := range hlist {652 deleteMessage(hid)653 }654 }655}656// helper function to report timing of given function657func timing(name string, start time.Time) {658 if Config.Verbose > 0 {659 log.Printf("Function '%s' elapsed time: %v\n", name, time.Since(start))660 } else if name == "main" {661 log.Printf("elapsed time: %v\n", time.Since(start))662 }663}664func main() {665 var config string666 flag.StringVar(&config, "config", os.Getenv("HOME")+"/.goimapsyncrc", "config JSON file")667 var dryRun bool668 flag.BoolVar(&dryRun, "dryRun", false, "perform dry-run")669 var mid string670 flag.StringVar(&mid, "mid", "", "mail file or messageid to use")671 var folder string672 flag.StringVar(&folder, "folder", "INBOX", "folder to use")673 var op string674 flag.StringVar(&op, "op", "sync", "perform given operation")675 var profiler string676 flag.StringVar(&profiler, "profiler", "", "profiler file name")677 var version bool678 flag.BoolVar(&version, "version", false, "Show version")679 var verbose int680 flag.IntVar(&verbose, "verbose", 0, "verbosity level")681 flag.Usage = func() {682 fmt.Println("Usage: goimapsync [options]")683 flag.PrintDefaults()684 fmt.Println("Supported operations:")685 fmt.Println(" fetch-new: to get list of new messages from specified IMAP folder")686 fmt.Println(" fetch-all: to get list of all messages from specified IMAP folder")687 fmt.Println(" move : to move givem message on IMAP server, e.g. send to Spam")688 fmt.Println(" sync : to sync local maildir with IMAP server(s)")689 fmt.Println("Examples:")690 fmt.Println(" # fetch new messages from given IMAP folder")691 fmt.Println(" goimapsync -config config.json -op=fetch-new -folder=MyFolder")692 fmt.Println(" # fetch all messages from given IMAP folder")693 fmt.Println(" goimapsync -config config.json -op=fetch-all -folder=MyFolder")694 fmt.Println(" # sync mails form local maildir to IMAP")695 fmt.Println(" goimapsync -config config.json -op=sync")696 fmt.Println(" # the same operation with encrypted (gpg) config")697 fmt.Println(" gpg -d -o - $HOME/.goimapsync.gpg | goimapsync -op=sync -config -")698 fmt.Println(" # sync mails form given IMAP folder into local maildir")699 fmt.Println(" gpg -d -o - $HOME/.goimapsync.gpg | goimapsync -config config.json -op=fetch -folder=MyFolder")700 fmt.Println(" # move given mail id in IMAP server to given folder")701 fmt.Println(" goimapsync -config config.json -op=move -mid=123 -folder=MyFolder")702 }703 flag.Parse()704 if version {705 fmt.Println(info())706 os.Exit(0)707 }708 ParseConfig(config)709 log.SetFlags(log.LstdFlags)710 // overwrite verbose level in config711 if verbose > 0 {712 Config.Verbose = verbose713 log.SetFlags(log.LstdFlags | log.Lshortfile)714 }715 if profiler != "" {716 Config.Profiler = profiler717 initProfiler(profiler)718 }719 // add timing profile720 defer timing("main", time.Now())721 // init imap folders map722 var err error723 imapFolders = make(map[string][]string)724 hostname, err = os.Hostname()725 if err != nil {726 log.Fatal(err)727 }728 // init our message db729 mdb, err = InitDB()730 if err != nil {731 log.Fatal(err)732 }733 // connect to our IMAP servers734 cmap := connect()735 defer logout(cmap)736 for imapName, c := range cmap {737 folders := getImapFolders(c, imapName)738 imapFolders[imapName] = folders739 if Config.Verbose > 0 {740 log.Println("IMAP", imapName, folders)741 }742 }743 switch op {744 case "move":745 // perform move action for given message id and IMAP folder746 for name, c := range cmap {747 Move(c, name, mid, folder)748 }749 case "fetch-new":750 // fetch new messages for given IMAP folder751 for name, c := range cmap {752 Fetch(c, name, folder, true)753 }754 case "fetch-all":755 // fetch all messages (old and new) for given IMAP folder756 for name, c := range cmap {757 Fetch(c, name, folder, false)758 }759 case "sync":760 // sync emails between local maildir and IMAP server761 Sync(cmap, dryRun)762 default:763 log.Fatalf("Given operation '%s' is not supported, please use sync, fetch-new, fetch-all\n", op)764 }765}...

Full Screen

Full Screen

imap.go

Source:imap.go Github

copy

Full Screen

...341 return nil, nil342 }343 var seqSet imap.SeqSet344 seqSet.AddRange(uint32(from), uint32(to))345 fetch := []imap.FetchItem{346 imap.FetchFlags,347 imap.FetchEnvelope,348 imap.FetchUid,349 imap.FetchBodyStructure,350 }351 ch := make(chan *imap.Message, 10)352 done := make(chan error, 1)353 go func() {354 done <- conn.Fetch(&seqSet, fetch, ch)355 }()356 msgs := make([]IMAPMessage, 0, to-from)357 for msg := range ch {358 msgs = append(msgs, IMAPMessage{msg, mbox.Name})359 }360 if err := <-done; err != nil {361 return nil, fmt.Errorf("failed to fetch message list: %v", err)362 }363 // Reverse list of messages364 for i := len(msgs)/2 - 1; i >= 0; i-- {365 opp := len(msgs) - 1 - i366 msgs[i], msgs[opp] = msgs[opp], msgs[i]367 }368 return msgs, nil369}370func searchMessages(conn *imapclient.Client, mboxName, query string, page, messagesPerPage int) (msgs []IMAPMessage, total int, err error) {371 if err := ensureMailboxSelected(conn, mboxName); err != nil {372 return nil, 0, err373 }374 criteria := PrepareSearch(query)375 nums, err := conn.Search(criteria)376 if err != nil {377 return nil, 0, fmt.Errorf("UID SEARCH failed: %v", err)378 }379 total = len(nums)380 from := page * messagesPerPage381 to := from + messagesPerPage382 if from >= len(nums) {383 return nil, total, nil384 }385 if to > len(nums) {386 to = len(nums)387 }388 nums = nums[from:to]389 indexes := make(map[uint32]int)390 for i, num := range nums {391 indexes[num] = i392 }393 var seqSet imap.SeqSet394 seqSet.AddNum(nums...)395 fetch := []imap.FetchItem{396 imap.FetchEnvelope,397 imap.FetchFlags,398 imap.FetchUid,399 imap.FetchBodyStructure,400 }401 ch := make(chan *imap.Message, 10)402 done := make(chan error, 1)403 go func() {404 done <- conn.Fetch(&seqSet, fetch, ch)405 }()406 msgs = make([]IMAPMessage, len(nums))407 for msg := range ch {408 i, ok := indexes[msg.SeqNum]409 if !ok {410 continue411 }412 msgs[i] = IMAPMessage{msg, mboxName}413 }414 if err := <-done; err != nil {415 return nil, 0, fmt.Errorf("failed to fetch message list: %v", err)416 }417 return msgs, total, nil418}419func getMessagePart(conn *imapclient.Client, mboxName string, uid uint32, partPath []int) (*IMAPMessage, *message.Entity, error) {420 if err := ensureMailboxSelected(conn, mboxName); err != nil {421 return nil, nil, err422 }423 seqSet := new(imap.SeqSet)424 seqSet.AddNum(uid)425 var partHeaderSection imap.BodySectionName426 partHeaderSection.Peek = true427 if len(partPath) > 0 {428 partHeaderSection.Specifier = imap.MIMESpecifier429 } else {430 partHeaderSection.Specifier = imap.HeaderSpecifier431 }432 partHeaderSection.Path = partPath433 var partBodySection imap.BodySectionName434 if len(partPath) > 0 {435 partBodySection.Specifier = imap.EntireSpecifier436 } else {437 partBodySection.Specifier = imap.TextSpecifier438 }439 partBodySection.Path = partPath440 fetch := []imap.FetchItem{441 imap.FetchEnvelope,442 imap.FetchUid,443 imap.FetchBodyStructure,444 imap.FetchFlags,445 imap.FetchRFC822Size,446 partHeaderSection.FetchItem(),447 partBodySection.FetchItem(),448 }449 ch := make(chan *imap.Message, 1)450 if err := conn.UidFetch(seqSet, fetch, ch); err != nil {451 return nil, nil, fmt.Errorf("failed to fetch message: %v", err)452 }453 msg := <-ch454 if msg == nil {455 return nil, nil, fmt.Errorf("server didn't return message")456 }457 body := msg.GetBody(&partHeaderSection)458 if body == nil {459 return nil, nil, fmt.Errorf("server didn't return message")460 }461 headerReader := bufio.NewReader(body)462 h, err := textproto.ReadHeader(headerReader)463 if err != nil {464 return nil, nil, fmt.Errorf("failed to read part header: %v", err)465 }...

Full Screen

Full Screen

fetch.go

Source:fetch.go Github

copy

Full Screen

1package imap2import (3 "bufio"4 "fmt"5 "github.com/emersion/go-imap"6 "github.com/emersion/go-message"7 _ "github.com/emersion/go-message/charset"8 "github.com/emersion/go-message/mail"9 "github.com/emersion/go-message/textproto"10 "git.sr.ht/~sircmpwn/aerc/models"11 "git.sr.ht/~sircmpwn/aerc/worker/types"12)13func (imapw *IMAPWorker) handleFetchMessageHeaders(14 msg *types.FetchMessageHeaders) {15 imapw.worker.Logger.Printf("Fetching message headers")16 section := &imap.BodySectionName{17 BodyPartName: imap.BodyPartName{18 Specifier: imap.HeaderSpecifier,19 },20 Peek: true,21 }22 items := []imap.FetchItem{23 imap.FetchBodyStructure,24 imap.FetchEnvelope,25 imap.FetchInternalDate,26 imap.FetchFlags,27 imap.FetchUid,28 section.FetchItem(),29 }30 imapw.handleFetchMessages(msg, msg.Uids, items,31 func(_msg *imap.Message) error {32 reader := _msg.GetBody(section)33 textprotoHeader, err := textproto.ReadHeader(bufio.NewReader(reader))34 if err != nil {35 return fmt.Errorf("could not read header: %v", err)36 }37 header := &mail.Header{message.Header{textprotoHeader}}38 imapw.worker.PostMessage(&types.MessageInfo{39 Message: types.RespondTo(msg),40 Info: &models.MessageInfo{41 BodyStructure: translateBodyStructure(_msg.BodyStructure),42 Envelope: translateEnvelope(_msg.Envelope),43 Flags: translateImapFlags(_msg.Flags),44 InternalDate: _msg.InternalDate,45 RFC822Headers: header,46 Uid: _msg.Uid,47 },48 }, nil)49 return nil50 })51}52func (imapw *IMAPWorker) handleFetchMessageBodyPart(53 msg *types.FetchMessageBodyPart) {54 imapw.worker.Logger.Printf("Fetching message part")55 var partHeaderSection imap.BodySectionName56 partHeaderSection.Peek = true57 if len(msg.Part) > 0 {58 partHeaderSection.Specifier = imap.MIMESpecifier59 } else {60 partHeaderSection.Specifier = imap.HeaderSpecifier61 }62 partHeaderSection.Path = msg.Part63 var partBodySection imap.BodySectionName64 if len(msg.Part) > 0 {65 partBodySection.Specifier = imap.EntireSpecifier66 } else {67 partBodySection.Specifier = imap.TextSpecifier68 }69 partBodySection.Path = msg.Part70 items := []imap.FetchItem{71 imap.FetchEnvelope,72 imap.FetchUid,73 imap.FetchBodyStructure,74 imap.FetchFlags,75 partHeaderSection.FetchItem(),76 partBodySection.FetchItem(),77 }78 imapw.handleFetchMessages(msg, []uint32{msg.Uid}, items,79 func(_msg *imap.Message) error {80 headerReader := bufio.NewReader(_msg.GetBody(&partHeaderSection))81 h, err := textproto.ReadHeader(headerReader)82 if err != nil {83 return fmt.Errorf("failed to read part header: %v", err)84 }85 part, err := message.New(message.Header{h},86 _msg.GetBody(&partBodySection))87 if err != nil {88 return fmt.Errorf("failed to create message reader: %v", err)89 }90 imapw.worker.PostMessage(&types.MessageBodyPart{91 Message: types.RespondTo(msg),92 Part: &models.MessageBodyPart{93 Reader: part.Body,94 Uid: _msg.Uid,95 },96 }, nil)97 // Update flags (to mark message as read)98 imapw.worker.PostMessage(&types.MessageInfo{99 Message: types.RespondTo(msg),100 Info: &models.MessageInfo{101 Flags: translateImapFlags(_msg.Flags),102 Uid: _msg.Uid,103 },104 }, nil)105 return nil106 })107}108func (imapw *IMAPWorker) handleFetchFullMessages(109 msg *types.FetchFullMessages) {110 imapw.worker.Logger.Printf("Fetching full messages")111 section := &imap.BodySectionName{}112 items := []imap.FetchItem{113 imap.FetchEnvelope,114 imap.FetchFlags,115 imap.FetchUid,116 section.FetchItem(),117 }118 imapw.handleFetchMessages(msg, msg.Uids, items,119 func(_msg *imap.Message) error {120 r := _msg.GetBody(section)121 if r == nil {122 return fmt.Errorf("could not get section %#v", section)123 }124 imapw.worker.PostMessage(&types.FullMessage{125 Message: types.RespondTo(msg),126 Content: &models.FullMessage{127 Reader: bufio.NewReader(r),128 Uid: _msg.Uid,129 },130 }, nil)131 // Update flags (to mark message as read)132 imapw.worker.PostMessage(&types.MessageInfo{133 Message: types.RespondTo(msg),134 Info: &models.MessageInfo{135 Flags: translateImapFlags(_msg.Flags),136 Uid: _msg.Uid,137 },138 }, nil)139 return nil140 })141}142func (imapw *IMAPWorker) handleFetchMessages(143 msg types.WorkerMessage, uids []uint32, items []imap.FetchItem,144 procFunc func(*imap.Message) error) {145 messages := make(chan *imap.Message)146 done := make(chan error)147 go func() {148 var reterr error149 for _msg := range messages {150 imapw.seqMap[_msg.SeqNum-1] = _msg.Uid151 err := procFunc(_msg)152 if err != nil {153 if reterr == nil {154 reterr = err155 }156 // drain the channel upon error157 for range messages {158 }159 }160 }161 done <- reterr162 }()163 emitErr := func(err error) {164 imapw.worker.PostMessage(&types.Error{165 Message: types.RespondTo(msg),166 Error: err,167 }, nil)168 }169 set := toSeqSet(uids)170 if err := imapw.client.UidFetch(set, items, messages); err != nil {171 emitErr(err)172 return173 }174 if err := <-done; err != nil {175 emitErr(err)176 return177 }178 imapw.worker.PostMessage(179 &types.Done{types.RespondTo(msg)}, nil)180}...

Full Screen

Full Screen

fetch

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 if err != nil {4 log.Fatal(err)5 }6 defer resp.Body.Close()7 body, err := ioutil.ReadAll(resp.Body)8 if err != nil {9 log.Fatal(err)10 }11 fmt.Println(string(body))12}13import (14func main() {15 if err != nil {16 log.Fatal(err)17 }18 defer resp.Body.Close()19 body, err := ioutil.ReadAll(resp.Body)20 if err != nil {21 log.Fatal(err)22 }23 fmt.Println(string(body))24}25import (26func main() {27 if err != nil {28 log.Fatal(err)29 }30 defer resp.Body.Close()31 body, err := ioutil.ReadAll(resp.Body)32 if err != nil {33 log.Fatal(err)34 }35 fmt.Println(string(body))36}37import (38func main() {39 if err != nil {40 log.Fatal(err)41 }42 defer resp.Body.Close()43 body, err := ioutil.ReadAll(resp.Body)44 if err != nil {45 log.Fatal(err)46 }47 fmt.Println(string(body))48}49import (50func main() {51 if err != nil {52 log.Fatal(err)53 }54 defer resp.Body.Close()

Full Screen

Full Screen

fetch

Using AI Code Generation

copy

Full Screen

1imap_fetch($mbox, $msgno, $options);2imap_fetch($mbox, $msgno, $options);3imap_fetch($mbox, $msgno, $options);4imap_fetch($mbox, $msgno, $options);5imap_fetch($mbox, $msgno, $options);6imap_fetch($mbox, $msgno, $options);7imap_fetch($mbox, $msgno, $options);8imap_fetch($mbox, $msgno, $options);9imap_fetch($mbox, $msgno, $options);10imap_fetch($mbox, $msgno, $options);11imap_fetch($mbox, $msgno, $options);12imap_fetch($mbox, $msgno, $options);13imap_fetch($mbox, $msgno, $options);14imap_fetch($mbox, $msgno, $options);15imap_fetch($mbox, $msgno, $options);16imap_fetch($mbox, $msgno, $options);17imap_fetch($mbox, $msgno, $options);

Full Screen

Full Screen

fetch

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 criteria := imap.NewSearchCriteria()4 criteria.WithoutFlags = []string{imap.SeenFlag}5 seqNums, err := imapClient.Search(criteria)6 if err != nil {7 panic(err)8 }9 seqSet := new(imap.SeqSet)10 seqSet.AddNum(seqNums...)11 messages := make(chan *imap.Message)12 go func() {13 if err := imapClient.Fetch(seqSet, []imap.FetchItem{imap.FetchRFC822}, messages); err != nil {14 panic(err)15 }16 }()17 for msg := range messages {18 fmt.Println("Message:")19 fmt.Println(msg.GetBody(imap.FetchRFC822))20 }21}22import (23func main() {24 criteria := imap.NewSearchCriteria()25 criteria.WithoutFlags = []string{imap.SeenFlag}26 seqNums, err := imapClient.Search(criteria)27 if err != nil {28 panic(err)29 }30 seqSet := new(imap.SeqSet)31 seqSet.AddNum(seqNums...)32 messages := make(chan *imap.Message)33 go func() {34 if err := imapClient.Fetch(seqSet, []imap.FetchItem{imap.FetchRFC822}, messages); err != nil {35 panic(err)36 }37 }()38 for msg := range messages {39 fmt.Println("Message:")40 fmt.Println(msg.GetBody(imap.FetchRFC822))41 }42}43import (44func main() {45 criteria := imap.NewSearchCriteria()46 criteria.WithoutFlags = []string{imap.Seen

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Venom automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful