英文:
Golang Gmail imap search is freezing
问题
我正在尝试搜索特定发件人或特定标记。当我选择收件箱并在特定字符串上进行搜索时,搜索 API 会冻结。我不确定我做错了什么。我也找不到太多的示例。
criteria := imap.NewSearchCriteria()
criteria.WithoutFlags = []string{"\\Seen"}
uids, err := c.Search(criteria)
if err != nil {
 log.Println(err)
}
seqset := new(imap.SeqSet)
seqset.AddNum(uids...)
section := &imap.BodySectionName{}
items := []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchInternalDate, section.FetchItem()}
messages := make(chan *imap.Message)
go func() {
    done <- c.Fetch(seqset, items, messages)
}()
msg := <-messages // 它在这一点上被卡住了。什么都不会发生,我收不到消息。
请注意,这是一段代码,我只翻译了其中的注释部分。
英文:
I am trying to do a search for specific sender or specific flag. When I select Inbox and do a search on specific string the search api freezes. I am not sure what am I doing wrong. I am not able to find much examples too.
criteria := imap.NewSearchCriteria()
criteria.WithoutFlags = []string{"\\Seen"}
uids, err := c.Search(criteria)
if err != nil {
 log.Println(err)
}
seqset := new(imap.SeqSet)
seqset.AddNum(uids...)
section := &imap.BodySectionName{}
items := []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchInternalDate, section.FetchItem()}
messages := make(chan *imap.Message)
go func() {
	done <- c.Fetch(seqset, items, messages)
}()
msg := <-messages //its getting stuck at this point. Nothing happens i dont get messages.
答案1
得分: 2
当你的搜索可能返回多条消息时,你需要确保从messages通道中读取所有内容,否则程序将会挂起。所以,不要使用以下方式:
msg := <-messages
而是使用以下方式循环遍历通道:
for msg := range messages {
  // 处理消息
}
这是一个可以工作的示例,它从环境中获取连接详细信息。这是从emersion的imap库修改的示例:
package main
import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"os"
	"time"
	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/client"
)
func main() {
	hours := flag.Int("hours", 24, "look this many hours in the past for messages")
	flag.Parse()
	if *hours > 0 {
		*hours = *hours * -1
	}
	host := os.Getenv("IMAP_HOST")
	port := os.Getenv("IMAP_PORT")
	user := os.Getenv("IMAP_USER")
	pass := os.Getenv("IMAP_PASS")
	tlsn := os.Getenv("IMAP_TLS_SERVERNAME")
	if port == "" {
		port = "993"
	}
	connStr := fmt.Sprintf("%s:%s", host, port)
	tlsc := &tls.Config{}
	if tlsn != "" {
		tlsc.ServerName = tlsn
	}
	c, err := client.DialTLS(connStr, tlsc)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Connected")
	defer c.Logout()
	if err := c.Login(user, pass); err != nil {
		log.Fatal(err)
	}
	log.Println("Authenticated")
	mbox, err := c.Select("INBOX", false)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Flags for INBOX:", mbox.Flags)
	criteria := imap.NewSearchCriteria()
	//criteria.WithFlags = []string{imap.SeenFlag}
	criteria.Since = time.Now().Add(time.Duration(*hours) * time.Hour)
	uids, err := c.Search(criteria)
	if err != nil {
		log.Println(err)
	}
	seqset := new(imap.SeqSet)
	seqset.AddNum(uids...)
	log.Printf("Search complete, found %d messages", len(uids))
	section := &imap.BodySectionName{}
	items := []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchInternalDate, section.FetchItem()}
	messages := make(chan *imap.Message)
	done := make(chan error, 1)
	go func() {
		done <- c.Fetch(seqset, items, messages)
		log.Println("Fetch complete")
	}()
	for msg := range messages {
		if msg != nil {
			log.Printf("got message with address %p\n", msg)
		} else {
			log.Println("no messages matched criteria")
		}
	}
	if err := <-done; err != nil {
		log.Fatal(err)
	}
}
英文:
When your search can return more than one message, you need to make sure to read everything from the messages channel, otherwise the program will hang. So instead of:
msg := <-messages
loop over the channel like so:
for msg := range messages {
  // process msg
}
Here's my working sample, which pulls connection details from the environment. It's a modified version of the example from emersion's imap lib:
package main
import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"os"
	"time"
	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap/client"
)
func main() {
	hours := flag.Int("hours", 24, "look this many hours in the past for messages")
	flag.Parse()
	if *hours > 0 {
		*hours = *hours * -1
	}
	host := os.Getenv("IMAP_HOST")
	port := os.Getenv("IMAP_PORT")
	user := os.Getenv("IMAP_USER")
	pass := os.Getenv("IMAP_PASS")
	tlsn := os.Getenv("IMAP_TLS_SERVERNAME")
	if port == "" {
		port = "993"
	}
	connStr := fmt.Sprintf("%s:%s", host, port)
	tlsc := &tls.Config{}
	if tlsn != "" {
		tlsc.ServerName = tlsn
	}
	c, err := client.DialTLS(connStr, tlsc)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Connected")
	defer c.Logout()
	if err := c.Login(user, pass); err != nil {
		log.Fatal(err)
	}
	log.Println("Authenticated")
	mbox, err := c.Select("INBOX", false)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("Flags for INBOX:", mbox.Flags)
	criteria := imap.NewSearchCriteria()
	//criteria.WithFlags = []string{imap.SeenFlag}
	criteria.Since = time.Now().Add(time.Duration(*hours) * time.Hour)
	uids, err := c.Search(criteria)
	if err != nil {
		log.Println(err)
	}
	seqset := new(imap.SeqSet)
	seqset.AddNum(uids...)
	log.Printf("Search complete, found %d messages", len(uids))
	section := &imap.BodySectionName{}
	items := []imap.FetchItem{imap.FetchEnvelope, imap.FetchFlags, imap.FetchInternalDate, section.FetchItem()}
	messages := make(chan *imap.Message)
	done := make(chan error, 1)
	go func() {
		done <- c.Fetch(seqset, items, messages)
		log.Println("Fetch complete")
	}()
	for msg := range messages {
		if msg != nil {
			log.Printf("got message with address %p\n", msg)
		} else {
			log.Println("no messages matched criteria")
		}
	}
	if err := <-done; err != nil {
		log.Fatal(err)
	}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论