Go 如何获取IMAP消息的可见/不可见状态

Go 如何获取IMAP消息的可见/不可见状态,go,imap,Go,Imap,我已经通读了go和通用imap,但似乎找不到正确的方法来获取特定消息的状态——知道它是否标记为已读或未读 以下是到目前为止我得到的信息: // //Code that set up 'c' and 'cmd' ... // for cmd.InProgress() { // Wait for the next response (no timeout) c.Recv(-1) // Process command data for _, rsp = range

我已经通读了go和通用imap,但似乎找不到正确的方法来获取特定消息的状态——知道它是否标记为已读或未读

以下是到目前为止我得到的信息:

// 
//Code that set up 'c' and 'cmd' ...
//
for cmd.InProgress() {
    // Wait for the next response (no timeout)
    c.Recv(-1)

    // Process command data
    for _, rsp = range cmd.Data {
        if err != nil {
            fmt.Println(err)
        }
        header := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.HEADER"])  // Contains subject, from data
        uid := imap.AsNumber(rsp.MessageInfo().Attrs["UID"])  // Message unique id
        body := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.TEXT"])  // Message body
        //seenState := imap.AsBytes(rsp.MessageInfo().Attrs["Flags"])
        if msg, err := mail.ReadMessage(bytes.NewReader(header)); msg != nil {
            if err != nil {
                fmt.Println(err)
            }
            //START CUSTOM
            if strings.Contains(msg.Header.Get("Subject"), genUUID()){
                fmt.Println(rsp.Label)
                fmt.Println(rsp.MessageInfo().Attrs["Flags"])
                fmt.Println(c.Status("INBOX", string(uid)))
            }
            //END CUSTOM
对于输出,我得到:

FETCH
<nil>
LAOYU10 STATUS "INBOX" (Þ) <nil>
FETCH
LAOYU10“收件箱”状态(Þ)
我引用的文档使我相信,如果消息被标记为“看不见”,则至少应该打印我的一个方法。我错过了什么

编辑: 我正在测试一个包含四条消息的收件箱(gmail)。前两个已读,后两个未读。这是所有四条消息的输出

FETCH
<nil>
SIHLB7 STATUS "INBOX" (Û) <nil>
FETCH
<nil>
SIHLB8 STATUS "INBOX" (Ü) <nil>
FETCH
<nil>
SIHLB9 STATUS "INBOX" (Ý) <nil>
FETCH
<nil>
SIHLB10 STATUS "INBOX" (Þ) <nil>
FETCH
SIHLB7状态“收件箱”(Û)
取来
SIHLB8状态“收件箱”(Ü)
取来
SIHLB9状态“收件箱”(Ý)
取来
SIHLB10状态“收件箱”(Þ)

它为您打印
,因为没有设置任何标志,这意味着消息是“不可见的”。

每条消息在IMAP中都有一个标志列表,其中一个被称为\seen(与IMAP中的大多数内容一样,不区分大小写)。如果标志列表不包含该标志,则该消息将不可见


@jstedfast的答案解释了如何获取标志列表。剩下的问题是在空白处拆分并检查列表中的任何单词是否等于\seen。

需要注意的几件事是,确保您在imap请求中实际请求了flags字段。如果要发出fetch,则必须将
中的“FLAGS”
作为参数传递给
fetch
,此外,
Attrs
中的FLAGS属性区分大小写,因此需要
rsp.MessageInfo().Attrs[“FLAGS”]
。下面是在Gmail中使用imap和go imap库的工作示例,使用
Gmail\u EMAIL=EMAIL.address Gmail\u PASSWD=mypassword go run go\u file.go运行它

package main

import (
    "code.google.com/p/go-imap/go1/imap"
    "crypto/rand"
    "crypto/tls"
    "fmt"
    "os"
    "time"
)

func main() {
    label := "INBOX"
    email := os.Getenv("GMAIL_EMAIL")
    passwd := os.Getenv("GMAIL_PASSWD")

    conf := &tls.Config{
        Rand: rand.Reader,
    }

    c, err := imap.DialTLS("imap.gmail.com:993", conf)
    if err != nil {
        panic("Failed to connect")
    }

    defer c.Logout(30 * time.Second)

    c.Data = nil

    if c.Caps["STARTTLS"] {
        c.StartTLS(nil)
    }

    // Authenticate
    if c.State() == imap.Login {
        c.Login(email, passwd)
    }

    if c.State() != imap.Auth {
        panic("Authentication error")
    }

    c.Select(label, true)

    set, _ := imap.NewSeqSet("*")

    cmd, err := c.Fetch(set, "FLAGS", "UID")
    if err != nil {
        panic("Bad fetch command")
    }
    _, err = cmd.Result(imap.OK)
    if err != nil {
        panic("Bad fetch response")
    }
    for _, rsp := range cmd.Data {
        seen := false
        for _, flag := range imap.AsList(rsp.MessageInfo().Attrs["FLAGS"]) {
            if flag == "\\Seen" {
                seen = true
            }
        }

        if seen {
            fmt.Printf("Message %d has been read!\n", imap.AsNumber(rsp.MessageInfo().Attrs["UID"]))
        } else {
            fmt.Printf("Message %d has been not been read!\n", imap.AsNumber(rsp.MessageInfo().Attrs["UID"]))
        }
    }
}

对不起,我应该在我的问题中更清楚地说明我测试的对象。我对问题进行了编辑以包含此信息。实际上,根据go imap文档,设置的任何标志都不应返回空数组,flags属性区分大小写,应该是
“flags”
,而不是
“flags”
flags属性不区分大小写,参见RFC3501第81页。@arnt-我不在乎RFC是否说响应不区分大小写,@Morgoroth使用的库通过大写字母规范化所有响应——因此,正如我发布的,并且直接从库的源代码中读取,
Attrs
映射的正确键是
“FLAGS”
,而不是
“FLAGS”
“Flags”
或任何其他组合注意,您的
uid
变量的类型为
uint32
,除非您希望该数字是单个有效Unicode代码点的值,否则执行
string(uid)
(请参阅)。您可能需要或
fmt.Sprintf
。注意区分大小写。非常感谢!那么你认为这是文档中的一个输入错误吗?我从这一节中得到了“Flags”,特别是@Morgoroth:实际上,我没有仔细阅读MessageInfo结构文档,如果您注意到,
Flags
实际上是MessageInfo结构的一个属性,而不是Attrs中的一个键。该库似乎通过抓取
Attrs[“Flags”]
,在内部设置了Flags属性。因此,基本上您可以执行
imap.AsList(rsp.MessageInfo().Attrs[“FLAGS”])
调用,或者只需在
rsp.MessageInfo().FLAGS
上执行一个范围。这两种方法都可以工作,但是
rsp.MessageInfo().Attrs[“Flags”]
不会工作。
package main

import (
    "code.google.com/p/go-imap/go1/imap"
    "crypto/rand"
    "crypto/tls"
    "fmt"
    "os"
    "time"
)

func main() {
    label := "INBOX"
    email := os.Getenv("GMAIL_EMAIL")
    passwd := os.Getenv("GMAIL_PASSWD")

    conf := &tls.Config{
        Rand: rand.Reader,
    }

    c, err := imap.DialTLS("imap.gmail.com:993", conf)
    if err != nil {
        panic("Failed to connect")
    }

    defer c.Logout(30 * time.Second)

    c.Data = nil

    if c.Caps["STARTTLS"] {
        c.StartTLS(nil)
    }

    // Authenticate
    if c.State() == imap.Login {
        c.Login(email, passwd)
    }

    if c.State() != imap.Auth {
        panic("Authentication error")
    }

    c.Select(label, true)

    set, _ := imap.NewSeqSet("*")

    cmd, err := c.Fetch(set, "FLAGS", "UID")
    if err != nil {
        panic("Bad fetch command")
    }
    _, err = cmd.Result(imap.OK)
    if err != nil {
        panic("Bad fetch response")
    }
    for _, rsp := range cmd.Data {
        seen := false
        for _, flag := range imap.AsList(rsp.MessageInfo().Attrs["FLAGS"]) {
            if flag == "\\Seen" {
                seen = true
            }
        }

        if seen {
            fmt.Printf("Message %d has been read!\n", imap.AsNumber(rsp.MessageInfo().Attrs["UID"]))
        } else {
            fmt.Printf("Message %d has been not been read!\n", imap.AsNumber(rsp.MessageInfo().Attrs["UID"]))
        }
    }
}