### Complete IDLE Monitoring Example in Go Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-idle.md This example demonstrates a full IDLE session setup. It connects to an IMAP server, selects a folder, configures event handlers for new emails and deletions, starts the IDLE monitoring, and then stops it after a timeout. Ensure you have the go-imap library imported. ```go package main import ( "fmt" "log" "time" imap "github.com/BrianLeishman/go-imap" ) func main() { // Connect conn, err := imap.New("user@gmail.com", "password", "imap.gmail.com", 993) if err != nil { log.Fatal(err) } defer conn.Close() // Select folder if err := conn.SelectFolder("INBOX"); err != nil { log.Fatal(err) } // Set up handlers handler := &imap.IdleHandler{ OnExists: func(e imap.ExistsEvent) { fmt.Printf("[%s] šŸ“¬ New email! Total messages: %d\n", time.Now().Format("15:04:05"), e.MessageIndex) }, OnExpunge: func(e imap.ExpungeEvent) { fmt.Printf("[%s] šŸ—‘ļø Email deleted at position %d\n", time.Now().Format("15:04:05"), e.MessageIndex) }, OnFetch: func(e imap.FetchEvent) { fmt.Printf("[%s] šŸ“ Email %d flags: %v\n", time.Now().Format("15:04:05"), e.UID, e.Flags) }, } // Start IDLE fmt.Println("Starting IDLE monitoring...") if err := conn.StartIdle(handler); err != nil { log.Fatal(err) } // Monitor for 30 minutes fmt.Println("Monitoring active. Press Ctrl+C to exit.") select { case <-time.After(30 * time.Minute): fmt.Println("Timeout, stopping IDLE...") } // Stop IDLE if err := conn.StopIdle(); err != nil { log.Printf("Error stopping IDLE: %v\n", err) } fmt.Println("IDLE stopped.") } ``` -------------------------------- ### Complete IDLE Example Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-idle.md A comprehensive example demonstrating how to connect, select a folder, set up IDLE handlers, start IDLE monitoring, and stop IDLE. ```APIDOC ## Complete IDLE Example ### Description This example shows the full workflow of using the IDLE functionality, from connection to stopping the IDLE session. ### Code ```go package main import ( "fmt" "log" "time" imap "github.com/BrianLeishman/go-imap" ) func main() { // Connect conn, err := imap.New("user@gmail.com", "password", "imap.gmail.com", 993) if err != nil { log.Fatal(err) } defer conn.Close() // Select folder if err := conn.SelectFolder("INBOX"); err != nil { log.Fatal(err) } // Set up handlers handler := &imap.IdleHandler{ OnExists: func(e imap.ExistsEvent) { fmt.Printf("[%s] šŸ“¬ New email! Total messages: %d\n", time.Now().Format("15:04:05"), e.MessageIndex) }, OnExpunge: func(e imap.ExpungeEvent) { fmt.Printf("[%s] šŸ—‘ļø Email deleted at position %d\n", time.Now().Format("15:04:05"), e.MessageIndex) }, OnFetch: func(e imap.FetchEvent) { fmt.Printf("[%s] šŸ“ Email %d flags: %v\n", time.Now().Format("15:04:05"), e.UID, e.Flags) }, } // Start IDLE fmt.Println("Starting IDLE monitoring...") if err := conn.StartIdle(handler); err != nil { log.Fatal(err) } // Monitor for 30 minutes fmt.Println("Monitoring active. Press Ctrl+C to exit.") select { case <-time.After(30 * time.Minute): fmt.Println("Timeout, stopping IDLE...") } // Stop IDLE if err := conn.StopIdle(); err != nil { log.Printf("Error stopping IDLE: %v\n", err) } fmt.Println("IDLE stopped.") } ``` ``` -------------------------------- ### Install go-imap Client Source: https://github.com/brianleishman/go-imap/blob/master/README.md Use 'go get' to install the go-imap library. Requires Go 1.25+. ```bash go get github.com/BrianLeishman/go-imap ``` -------------------------------- ### Complete Configuration Example Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/configuration.md This example demonstrates setting various configuration options including timeouts, retry counts, verbose logging, and custom JSON logging before connecting to an IMAP server. ```go package main import ( "log/slog" "os" "time" imap "github.com/BrianLeishman/go-imap" ) func main() { // Set timeouts imap.DialTimeout = 10 * time.Second imap.CommandTimeout = 30 * time.Second // Configure retry behavior imap.RetryCount = 5 // Enable verbose logging imap.Verbose = true imap.SkipResponses = false // Configure custom JSON logging handler := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{ Level: slog.LevelInfo, AddSource: true, }) imap.SetSlogLogger(slog.New(handler)) // Now connect conn, err := imap.New("user@gmail.com", "password", "imap.gmail.com", 993) if err != nil { panic(err) } defer conn.Close() // All commands now use the configured settings } ``` -------------------------------- ### GetFolderStats Example Usage Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Example demonstrating how to fetch and process folder statistics, including handling per-folder errors. ```go stats, err := conn.GetFolderStats() if err != nil { log.Fatal(err) } for _, stat := range stats { if stat.Error != nil { fmt.Printf("%s [ERROR]: %v\n", stat.Name, stat.Error) } else { fmt.Printf("%s: %d emails (max UID: %d)\n", stat.Name, stat.Count, stat.MaxUID) } } ``` -------------------------------- ### List and Manage IMAP Folders Source: https://github.com/brianleishman/go-imap/blob/master/README.md Demonstrates how to list all folders, select folders for read/write or read-only operations, and manage folders by creating, renaming, and deleting them. Includes examples of getting total email counts with and without exclusions, and error-tolerant counting. ```go // List all folders folders, err := m.GetFolders() if err != nil { panic(err) } // Example output: // folders = []string{ // "INBOX", // "Sent", // "Drafts", // "Trash", // "INBOX/Receipts", // "INBOX/Important", // "[Gmail]/All Mail", // "[Gmail]/Spam", // } for _, folder := range folders { fmt.Println("Folder:", folder) } // Select a folder for operations (read-write mode) err = m.SelectFolder("INBOX") if err != nil { panic(err) } // Select folder in read-only mode err = m.ExamineFolder("INBOX") if err != nil { panic(err) } // Get total email count across all folders totalCount, err := m.GetTotalEmailCount() if err != nil { panic(err) } fmt.Printf("Total emails in all folders: %d\n", totalCount) // Get count excluding certain folders excludedFolders := []string{"Trash", "[Gmail]/Spam"} count, err := m.GetTotalEmailCountExcluding(excludedFolders) if err != nil { panic(err) } fmt.Printf("Total emails (excluding spam/trash): %d\n", count) // Error-tolerant counting (continues even if some folders fail) // This is especially useful with Gmail or other providers that have inaccessible system folders safeCount, folderErrors, err := m.GetTotalEmailCountSafe() if err != nil { panic(err) } fmt.Printf("Total accessible emails: %d\n", safeCount) if len(folderErrors) > 0 { fmt.Printf("Note: %d folders had errors:\n", len(folderErrors)) for _, folderErr := range folderErrors { fmt.Printf(" - %v\n", folderErr) } } // Example output: // Total accessible emails: 1247 // Note: 2 folders had errors: // - folder "[Gmail]": NO [NONEXISTENT] Unknown Mailbox // - folder "[Gmail]/All Mail": NO [NONEXISTENT] Unknown Mailbox // Create, rename, and delete folders err = m.CreateFolder("INBOX/Projects") if err != nil { panic(err) } err = m.RenameFolder("INBOX/Projects", "INBOX/Archive") if err != nil { panic(err) } err = m.DeleteFolder("INBOX/Archive") if err != nil { panic(err) } // Get detailed statistics for each folder (includes max UID) stats, err := m.GetFolderStats() if err != nil { panic(err) } fmt.Printf("Found %d folders:\n", len(stats)) for _, stat := range stats { if stat.Error != nil { fmt.Printf(" %-20s [ERROR]: %v\n", stat.Name, stat.Error) } else { fmt.Printf(" %-20s %5d emails, max UID: %d\n", stat.Name, stat.Count, stat.MaxUID) } } // Example output: // Found 8 folders: // INBOX 342 emails, max UID: 1543 // Sent 89 emails, max UID: 234 // Drafts 3 emails, max UID: 67 // Trash 12 emails, max UID: 89 // [Gmail] [ERROR]: NO [NONEXISTENT] Unknown Mailbox // [Gmail]/Spam 0 emails, max UID: 0 // INBOX/Archive 801 emails, max UID: 2156 // INBOX/Important 45 emails, max UID: 987 ``` -------------------------------- ### IMAP Idle Monitoring Example Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-idle.md Demonstrates how to start and stop IDLE monitoring with custom event handlers. Ensure a folder is selected before calling StartIdle. The IDLE mode runs in a background goroutine. ```go conn.SelectFolder("INBOX") handler := &imap.IdleHandler{ OnExists: func(e imap.ExistsEvent) { fmt.Printf("šŸ“¬ New message! Total: %d\n", e.MessageIndex) }, OnExpunge: func(e imap.ExpungeEvent) { fmt.Printf("šŸ—‘ļø Message deleted at index %d\n", e.MessageIndex) }, OnFetch: func(e imap.FetchEvent) { fmt.Printf("šŸ“ UID %d flags changed: %v\n", e.UID, e.Flags) }, } if err := conn.StartIdle(handler); err != nil { log.Fatal(err) } // IDLE runs in background, your code continues... fmt.Println("IDLE monitoring active...") time.Sleep(10 * time.Minute) if err := conn.StopIdle(); err != nil { log.Fatal(err) } ``` -------------------------------- ### CopyEmail Example Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-email-mutations.md Example demonstrating how to copy email with UID 245 to the 'INBOX/Backup' folder. The original email will remain in the current folder. ```go conn.SelectFolder("INBOX") if err := conn.CopyEmail(245, "INBOX/Backup"); err != nil { log.Fatal(err) } // Email now in both INBOX and INBOX/Backup ``` -------------------------------- ### Start IMAP IDLE Monitoring Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/MANIFEST.txt Begin monitoring the selected folder for real-time updates using the IMAP IDLE command. This example shows how to handle new messages arriving (OnExists). ```go conn.StartIdle(&imap.IdleHandler{ OnExists: func(e imap.ExistsEvent) { ... }, }) ``` -------------------------------- ### MoveEmail Example Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-email-mutations.md Example demonstrating how to move email with UID 245 to the 'INBOX/Archive' folder. After a successful move, the Dialer's current folder will be updated. ```go conn.SelectFolder("INBOX") if err := conn.MoveEmail(245, "INBOX/Archive"); err != nil { log.Fatal(err) } // Email moved and Folder now tracks "INBOX/Archive" ``` -------------------------------- ### Get Total Email Count Starting From and Excluding Folders (Go) Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Calculate the total email count starting from a specific folder while also excluding a list of other folders. An empty startFolder string will begin counting from the root. ```go func (d *Dialer) GetTotalEmailCountStartingFromExcluding(startFolder string, excludedFolders []string) (int, error) ``` -------------------------------- ### Example Usage of Flags Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/types.md Demonstrates how to construct a Flags struct to set or remove message flags and custom keywords. This example shows marking a message as read and starred, and managing custom keywords like '$Important' and '$Pending'. ```go flags := Flags{ Seen: FlagAdd, // Mark as read Flagged: FlagAdd, // Star the message Keywords: map[string]bool{ "$Important": true, // Add custom keyword "$Pending": false, // Remove custom keyword }, } conn.SetFlags(uid, flags) ``` -------------------------------- ### Example Usage of EmailAddresses Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/types.md Demonstrates how to populate and use the EmailAddresses type, including setting display names and handling cases with no display name. Shows the formatted output of the String() method. ```go email.From["john@example.com"] = "John Doe" email.To["jane@example.com"] = "" // No display name fmt.Println(email.From.String()) // "John Doe " ``` -------------------------------- ### Attachment.String() Example Usage Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-email-fetch.md Demonstrates how to use the String() method to get a formatted summary of an attachment. The output format is 'filename (mimetype humanized_size)'. ```go att := email.Attachments[0] fmt.Println(att.String()) // "invoice.pdf (application/pdf 125 kB)" ``` -------------------------------- ### StartIdle Function Signature Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-idle.md Defines the signature for starting IDLE monitoring. Requires an IdleHandler for event callbacks. ```go func (d *Dialer) StartIdle(handler *IdleHandler) error ``` -------------------------------- ### GetFolderStatsStartingFrom Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Retrieves folder statistics starting from a specified folder. ```APIDOC ## GetFolderStatsStartingFrom ### Description Returns folder statistics starting from a specific folder. ### Method Signature ```go func (d *Dialer) GetFolderStatsStartingFrom(startFolder string) ([]FolderStats, error) ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **[]FolderStats** (array) - A slice of FolderStats objects. - **error** (error) - An error object if the operation fails. ### Response Example None ``` -------------------------------- ### Complete Go IMAP Client Example Source: https://github.com/brianleishman/go-imap/blob/master/README.md This snippet shows a full workflow: configuring the library, connecting to an IMAP server, listing folders, selecting a mailbox, searching for unread emails, fetching and displaying email details, marking emails as read, retrieving mailbox statistics, and using the IDLE command to monitor for new emails. Ensure you replace placeholder credentials and server details with your actual information. ```go package main import ( "fmt" "log" "time" imap "github.com/BrianLeishman/go-imap" ) func main() { // Configure the library imap.Verbose = false imap.RetryCount = 3 imap.DialTimeout = 10 * time.Second imap.CommandTimeout = 30 * time.Second // Connect fmt.Println("Connecting to IMAP server...") m, err := imap.New("your-email@gmail.com", "your-password", "imap.gmail.com", 993) if err != nil { log.Fatalf("Connection failed: %v", err) } defer m.Close() // List folders fmt.Println("\nšŸ“ Available folders:") folders, err := m.GetFolders() if err != nil { log.Fatalf("Failed to get folders: %v", err) } for _, folder := range folders { fmt.Printf(" - %s\n", folder) } // Select INBOX fmt.Println("\nšŸ“„ Selecting INBOX...") if err := m.SelectFolder("INBOX"); err != nil { log.Fatalf("Failed to select INBOX: %v", err) } // Get unread emails fmt.Println("\nšŸ” Searching for unread emails...") unreadUIDs, err := m.GetUIDs("UNSEEN") if err != nil { log.Fatalf("Search failed: %v", err) } fmt.Printf("Found %d unread emails\n", len(unreadUIDs)) // Fetch first 5 unread (or less) limit := 5 if len(unreadUIDs) < limit { limit = len(unreadUIDs) } if limit > 0 { fmt.Printf("\nšŸ“§ Fetching first %d unread emails...\n", limit) emails, err := m.GetEmails(unreadUIDs[:limit]...) if err != nil { log.Fatalf("Failed to fetch emails: %v", err) } for uid, email := range emails { fmt.Printf("\n--- Email UID %d ---\n", uid) fmt.Printf("From: %s\n", email.From) fmt.Printf("Subject: %s\n", email.Subject) fmt.Printf("Date: %s\n", email.Sent.Format("Jan 2, 2006 3:04 PM")) fmt.Printf("Size: %.1f KB\n", float64(email.Size)/1024) if len(email.Text) > 100 { fmt.Printf("Preview: %.100s...\n", email.Text) } else if len(email.Text) > 0 { fmt.Printf("Preview: %s\n", email.Text) } if len(email.Attachments) > 0 { fmt.Printf("Attachments: %d\n", len(email.Attachments)) for _, att := range email.Attachments { fmt.Printf(" - %s (%.1f KB)\n", att.Name, float64(len(att.Content))/1024) } } // Mark first email as read if uid == unreadUIDs[0] { fmt.Printf("\nāœ“ Marking email %d as read...\n", uid) if err := m.MarkSeen(uid); err != nil { fmt.Printf("Failed to mark as read: %v\n", err) } } } } // Get some statistics fmt.Println("\nšŸ“Š Mailbox Statistics:") allUIDs, _ := m.GetUIDs("ALL") seenUIDs, _ := m.GetUIDs("SEEN") flaggedUIDs, _ := m.GetUIDs("FLAGGED") fmt.Printf(" Total emails: %d\n", len(allUIDs)) fmt.Printf(" Read emails: %d\n", len(seenUIDs)) fmt.Printf(" Unread emails: %d\n", len(allUIDs)-len(seenUIDs)) fmt.Printf(" Flagged emails: %d\n", len(flaggedUIDs)) // Start IDLE monitoring for 10 seconds fmt.Println("\nšŸ‘€ Monitoring for new emails (10 seconds)...") handler := &imap.IdleHandler{ OnExists: func(e imap.ExistsEvent) { fmt.Printf(" šŸ“¬ New email arrived! (message #%d)\n", e.MessageIndex) }, } if err := m.StartIdle(handler); err == nil { time.Sleep(10 * time.Second) _ = m.StopIdle() } fmt.Println("\nāœ… Done!") } ``` -------------------------------- ### Complete Working Example: Mailbox Statistics and Monitoring Source: https://github.com/brianleishman/go-imap/blob/master/README.md This snippet shows how to retrieve mailbox statistics (total, read, unread, flagged emails) and then monitor the mailbox for new emails over a specified duration. Ensure you have a valid IMAP connection established before running this. ```go /* Project: /brianleishman/go-imap ### 7. Complete Working Example šŸ“Š Mailbox Statistics: Total emails: 1532 Read emails: 1530 Unread emails: 2 Flagged emails: 23 šŸ‘€ Monitoring for new emails (10 seconds)... āœ… Done! */ ``` -------------------------------- ### Get Total Email Count Starting From Folder (Go) Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Retrieve the total email count from a specified folder onwards. This function skips all folders that appear before the startFolder. ```go func (d *Dialer) GetTotalEmailCountStartingFrom(startFolder string) (int, error) ``` ```go // Count emails from "Important" folder and all subsequent folders total, err := conn.GetTotalEmailCountStartingFrom("Important") ``` -------------------------------- ### GetFolderStatsStartingFromExcluding Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Retrieves folder statistics starting from a specified folder and excluding a list of other folders. ```APIDOC ## GetFolderStatsStartingFromExcluding ### Description Returns folder statistics with start and exclude options. ### Method Signature ```go func (d *Dialer) GetFolderStatsStartingFromExcluding(startFolder string, excludedFolders []string) ([]FolderStats, error) ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **[]FolderStats** (array) - A slice of FolderStats objects. - **error** (error) - An error object if the operation fails. ### Response Example None ``` -------------------------------- ### Example: Batch Delete and Expunge Emails Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-email-mutations.md Illustrates how to delete multiple emails by iterating through a list of UIDs and calling DeleteEmail for each, followed by a single call to Expunge to remove them all. This is an efficient way to clear multiple messages. ```go // Delete multiple emails for _, uid := range uidsToDelete { if err := conn.DeleteEmail(uid); err != nil { log.Fatal(err) } } // Permanently remove all marked messages if err := conn.Expunge(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Example: Delete and Expunge Email Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-email-mutations.md Demonstrates the typical workflow of selecting a folder, marking an email for deletion using DeleteEmail, and then permanently removing it with Expunge. Ensure Expunge is called after marking messages to complete the deletion. ```go conn.SelectFolder("INBOX") if err := conn.DeleteEmail(245); err != nil { log.Fatal(err) } if err := conn.Expunge(); err != nil { log.Fatal(err) } // Message permanently removed from server ``` -------------------------------- ### List Folders and Get Safe Email Count Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/quick-start.md Troubleshoot 'Unknown Mailbox' errors by listing available folders. Use GetTotalEmailCountSafe for potentially large mailboxes to avoid performance issues. ```go // List available folders to find correct name folders, _ := conn.GetFolders() for _, f := range folders { fmt.Println(f) } // Use safe counting for Gmail total, errs, _ := conn.GetTotalEmailCountSafe() ``` -------------------------------- ### Get Email Headers with Go IMAP Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/quick-start.md Fetch UIDs for unseen emails and then retrieve their headers. This is a fast way to get a summary of emails without downloading the full content. ```go uids, _ := conn.GetUIDs("UNSEEN") overviews, err := conn.GetOverviews(uids...) if err != nil { log.Fatal(err) } for uid, email := range overviews { fmt.Printf("UID %d: %s from %s\n", uid, email.Subject, email.From) } ``` -------------------------------- ### GetTotalEmailCountStartingFrom Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Retrieves the total email count starting from a specific folder and including all subsequent folders. ```APIDOC ## GetTotalEmailCountStartingFrom ### Description Returns total email count starting from a specific folder onward. ### Method (Not specified, likely a method on a Dialer struct) ### Parameters #### Path Parameters (None) #### Query Parameters (None) #### Request Body (None) ### Parameters - **startFolder** (string) - Required - Folder to start from (skips earlier folders) ### Returns - `int`: Total emails from startFolder onward - `error`: Error if any folder is inaccessible ### Example ```go // Count emails from "Important" folder and all subsequent folders total, err := conn.GetTotalEmailCountStartingFrom("Important") ``` ``` -------------------------------- ### Monitor Folder with IDLE in Go IMAP Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/quick-start.md Select a folder and start an IDLE connection to monitor for new emails in real-time. The handler processes events like new messages arriving. ```go if err := conn.SelectFolder("INBOX"); err != nil { log.Fatal(err) } handler := &imap.IdleHandler{ OnExists: func(e imap.ExistsEvent) { fmt.Printf("New email! Total messages: %d\n", e.MessageIndex) }, } if err := conn.StartIdle(handler); err != nil { log.Fatal(err) } // Monitor for 10 minutes time.Sleep(10 * time.Minute) if err := conn.StopIdle(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Logger Interface Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/types.md A logging interface used by the package. Supports debug, info, warn, and error levels, as well as adding attributes. See configuration.md for setup instructions. ```go type Logger interface { Debug(msg string, args ...any) Info(msg string, args ...any) Warn(msg string, args ...any) Error(msg string, args ...any) WithAttrs(args ...any) Logger } ``` -------------------------------- ### Get Gmail OAuth2 Access Token using golang.org/x/oauth2 Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/authentication.md This Go code demonstrates how to obtain an OAuth2 access token for Gmail using the golang.org/x/oauth2 library. It requires setting up your client ID, client secret, and scopes, and typically involves a browser-based OAuth2 flow. ```go import ( "golang.org/x/oauth2" "golang.org/x/oauth2/google" imap "github.com/BrianLeishman/go-imap" ) func getGmailToken() (string, error) { config := &oauth2.Config{ ClientID: "YOUR_CLIENT_ID.apps.googleusercontent.com", ClientSecret: "YOUR_CLIENT_SECRET", Scopes: []string{ "https://mail.google.com/", }, Endpoint: google.Endpoint, } // Use browser-based OAuth2 flow to get authorization code token, err := config.Exchange(ctx, authorizationCode) if err != nil { return "", err } return token.AccessToken, nil } // Use the token to connect accessToken, err := getGmailToken() if err != nil { log.Fatal(err) } conn, err := imap.NewWithOAuth2("user@gmail.com", accessToken, "imap.gmail.com", 993) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Handle IDLE Command Errors in Go Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/errors.md Check for specific error messages when starting or stopping the IDLE command to determine the cause, such as unsupported extensions or connection issues. Fall back to polling if IDLE fails. ```go err := conn.StartIdle(handler) if err != nil { log.Printf("IDLE failed: %v", err) if strings.Contains(err.Error(), "already entering") { // IDLE already running } else if strings.Contains(err.Error(), "timeout") { // Server didn't respond to IDLE } else { // IDLE may not be supported log.Printf("Server may not support IDLE extension") } // Fall back to polling instead return } err = conn.StopIdle() if err != nil { log.Printf("Failed to stop IDLE: %v", err) // IDLE may have already disconnected // Reconnect manually conn.Reconnect() } ``` -------------------------------- ### Monitor IMAP for Real-Time Updates (IDLE) Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/README.md Enable real-time monitoring of the selected folder using the IMAP IDLE command. This allows the client to receive notifications for new emails without constant polling. Requires starting and stopping the IDLE session. ```go if err := conn.SelectFolder("INBOX"); err != nil { log.Fatal(err) } handler := &imap.IdleHandler{ OnExists: func(e imap.ExistsEvent) { fmt.Printf("New email! Total: %d\n", e.MessageIndex) }, } if err := conn.StartIdle(handler); err != nil { log.Fatal(err) } // ... monitor for a while ... if err := conn.StopIdle(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Connect and Authenticate with Password (LOGIN) Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/quick-start.md Establish a connection to an IMAP server using username and password authentication. Ensure to close the connection when done. ```go conn, err := imap.New("user@example.com", "password", "imap.example.com", 993) if err != nil { log.Fatal(err) } defer conn.Close() ``` -------------------------------- ### Manage Folder State with SelectFolder and ExamineFolder Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/architecture.md Folder selection is explicit and tracked by the connection. Use `SelectFolder` for read-write access and `ExamineFolder` for read-only access. All subsequent operations will use the currently selected folder. ```go // Folder selection changes state conn.SelectFolder("INBOX") // conn.Folder = "INBOX", conn.ReadOnly = false conn.ExamineFolder("Archive") // conn.Folder = "Archive", conn.ReadOnly = true // All operations use current folder uids, _ := conn.GetUIDs("ALL") // Searches in "Archive" // Must select new folder explicitly conn.SelectFolder("INBOX") // Back to INBOX ``` -------------------------------- ### Get Total Email Count Excluding Folders (Go) Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Use this function to get the total email count while skipping specified folders. It provides per-folder error handling for inaccessible folders. ```go func (d *Dialer) GetTotalEmailCountSafeExcluding(excludedFolders []string) (int, []error, error) ``` ```go total, errs, err := conn.GetTotalEmailCountSafeExcluding([]string{"Trash"}) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Go IMAP Command Flow: Search and Fetch Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/architecture.md Illustrates the step-by-step process of a Search and Fetch command within the Go IMAP client, from user invocation to response parsing. ```text User Code: conn.SearchUIDs(builder) ↓ Dialer.SearchUIDs() ↓ Dialer.GetUIDs(criteria) ↓ Dialer.Exec("UID SEARCH ...") ↓ Protocol Layer: execOnce() ↓ Write command: "TAG UID SEARCH ...\r\n" ↓ Read response loop ↓ readLiterals() if needed ↓ Call processLine() callback ↓ Continue until "TAG OK" received ↓ Parse Response: parseUIDSearchResponse(rawResponse) ↓ Extract UIDs from "* SEARCH 1 2 3" ↓ Return: []int{1, 2, 3} ``` -------------------------------- ### GetTotalEmailCountStartingFromExcluding Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Retrieves the total email count starting from a specified folder while excluding a list of other folders. ```APIDOC ## GetTotalEmailCountStartingFromExcluding ### Description Returns total email count starting from a folder and excluding specific folders. ### Method (Not specified, likely a method on a Dialer struct) ### Parameters #### Path Parameters (None) #### Query Parameters (None) #### Request Body (None) ### Parameters - **startFolder** (string) - Required - Folder to start from (empty string means start from beginning) - **excludedFolders** ([]string) - Required - Folders to exclude ### Returns - `int`: Total emails - `error`: Error from any folder ### Example (No example provided in source) ``` -------------------------------- ### Connect, Search, and Fetch Emails with Go IMAP Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/quick-start.md Connect to an IMAP server, select the INBOX, search for unread emails from the last week, fetch their headers, and mark the first found email as read. Ensure you have the correct email address, password, server address, and port. ```go package main import ( "fmt" "log" "time" imap "github.com/BrianLeishman/go-imap" ) func main() { // Connect conn, err := imap.New("user@gmail.com", "password", "imap.gmail.com", 993) if err != nil { log.Fatal(err) } defer conn.Close() // Select INBOX if err := conn.SelectFolder("INBOX"); err != nil { log.Fatal(err) } // Find unread emails from last week lastWeek := time.Now().AddDate(0, 0, -7) uids, err := conn.SearchUIDs( imap.Search().Unseen().Since(lastWeek), ) if err != nil { log.Fatal(err) } fmt.Printf("Found %d unread emails from last week\n", len(uids)) // Fetch headers overviews, err := conn.GetOverviews(uids...) if err != nil { log.Fatal(err) } // Display for uid, email := range overviews { fmt.Printf("UID %d: %s from %s (received %s)\n", uid, email.Subject, email.From, email.Received.Format("2006-01-02")) // Mark first as read if uid == uids[0] { _ = conn.MarkSeen(uid) } } } ``` -------------------------------- ### Import IMAP Library Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/MANIFEST.txt Import the go-imap library for use in your Go project. ```go import imap "github.com/BrianLeishman/go-imap" ``` -------------------------------- ### GetTotalEmailCountSafeStartingFrom Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Retrieves the total email count from accessible folders starting from a specified folder, with per-folder error handling. ```APIDOC ## GetTotalEmailCountSafeStartingFrom ### Description Returns total email count starting from a folder with per-folder error handling. ### Method Signature ```go func (d *Dialer) GetTotalEmailCountSafeStartingFrom(startFolder string) (int, []error, error) ``` ### Parameters #### Path Parameters - **startFolder** (string) - Required - Folder to start from ### Returns - **int**: Total emails from accessible folders - **[]error**: Folder errors - **error**: Critical error ``` -------------------------------- ### GetTotalEmailCountSafeStartingFromExcluding Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Retrieves the total email count with options for filtering and error handling, starting from a specified folder and excluding certain folders. ```APIDOC ## GetTotalEmailCountSafeStartingFromExcluding ### Description Returns total email count with all options for filtering and error handling. ### Method Signature ```go func (d *Dialer) GetTotalEmailCountSafeStartingFromExcluding(startFolder string, excludedFolders []string) (int, []error, error) ``` ### Parameters #### Path Parameters - **startFolder** (string) - Required - Folder to start from - **excludedFolders** ([]string) - Required - List of folders to exclude ### Returns - **int**: Total emails from accessible folders - **[]error**: Folder errors - **error**: Critical error ``` -------------------------------- ### Move and Copy Emails in Go Source: https://github.com/brianleishman/go-imap/blob/master/README.md Demonstrates moving emails to a different folder using MoveEmail and copying them using CopyEmail. MoveEmail removes the original, while CopyEmail keeps it. Both require the target folder name. ```go // === Moving and Copying Emails === uid := 245 err = m.MoveEmail(uid, "INBOX/Archive") if err != nil { panic(err) } fmt.Printf("Moved email %d to Archive\n", uid) // Copy keeps the original in the current folder err = m.CopyEmail(uid, "INBOX/Backup") if err != nil { panic(err) } fmt.Printf("Copied email %d to Backup\n", uid) ``` -------------------------------- ### Search Emails by Criteria Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/MANIFEST.txt Search for emails within the selected folder using a type-safe builder API. This example searches for unseen emails from a specific sender. ```go uids, _ := conn.SearchUIDs(imap.Search().Unseen().From("alice@example.com")) ``` -------------------------------- ### Safely Count Emails Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/README.md Get the total email count while safely handling inaccessible folders, compatible with services like Gmail. Logs errors for skipped folders. ```go // Count emails, skipping inaccessible folders total, folderErrors, err := conn.GetTotalEmailCountSafe() if err != nil { log.Fatal(err) } fmt.Printf("Total: %d\n", total) for _, e := range folderErrors { log.Printf("Skipped: %v\n", e) } ``` -------------------------------- ### New Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-dialer.md Creates a new IMAP connection using LOGIN authentication. It establishes a TLS connection, retries connection attempts, and respects dial timeouts. ```APIDOC ## New ### Description Creates a new IMAP connection using LOGIN authentication. ### Method `func New(username, password, host string, port int) (*Dialer, error)` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go conn, err := imap.New("user@gmail.com", "password", "imap.gmail.com", 993) if err != nil { log.Fatal(err) } defer conn.Close() ``` ### Response #### Success Response - `*Dialer`: Authenticated connection to IMAP server - `error`: nil on success #### Response Example None explicitly defined, but returns a *Dialer object on success. ``` -------------------------------- ### Create Independent Connection Clone Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/architecture.md Use `Clone()` to create an independent connection with the same configuration as an existing one. This is useful for managing state and allowing parallel operations when a single connection is insufficient. ```go conn, _ := imap.New(...) clone, _ := conn.Clone() // Independent connection, same config ``` -------------------------------- ### Create a SearchBuilder Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-search.md Use the `Search()` function to create a new SearchBuilder instance. This builder is used to fluently construct IMAP search criteria. ```go builder := imap.Search().From("alice@example.com").Unseen().Since(lastWeek) ``` -------------------------------- ### StartIdle Method Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-idle.md Initiates IDLE monitoring on the IMAP connection, handling events via a provided handler and managing reconnections automatically. ```APIDOC ## StartIdle ```go func (d *Dialer) StartIdle(handler *IdleHandler) error ``` Starts IDLE monitoring with automatic reconnection. **Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | handler | *IdleHandler | yes | Callback handlers for events | **Returns:** - `error`: Error starting IDLE (immediate errors only) **Behavior:** - Runs IDLE in a background goroutine - Automatically refreshes IDLE every 5 minutes (per RFC) - Automatically reconnects if connection is lost - Restores folder selection on reconnect - Only fails immediately if IDLE cannot be entered (e.g., wrong folder selection) **Requires:** - A folder must be selected before calling `StartIdle()` - Use `SelectFolder()` first **Example:** ```go conn.SelectFolder("INBOX") handler := &imap.IdleHandler{ OnExists: func(e imap.ExistsEvent) { fmt.Printf("šŸ“¬ New message! Total: %d\n", e.MessageIndex) }, OnExpunge: func(e imap.ExpungeEvent) { fmt.Printf("šŸ—‘ļø Message deleted at index %d\n", e.MessageIndex) }, OnFetch: func(e imap.FetchEvent) { fmt.Printf("šŸ“ UID %d flags changed: %v\n", e.UID, e.Flags) }, } if err := conn.StartIdle(handler); err != nil { log.Fatal(err) } // IDLE runs in background, your code continues... fmt.Println("IDLE monitoring active...") time.Sleep(10 * time.Minute) if err := conn.StopIdle(); err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### Get Total Email Count Excluding Folders Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-folders.md Retrieves the total email count, skipping specified folders. Use this when you need a count of emails in active, non-archived, or non-junk folders. ```go func (d *Dialer) GetTotalEmailCountExcluding(excludedFolders []string) (int, error) ``` ```go total, err := conn.GetTotalEmailCountExcluding([]string{"Trash", "[Gmail]/Spam"}) if err != nil { log.Fatal(err) } fmt.Printf("Active emails: %d\n", total) ``` -------------------------------- ### Get Maximum UID in Go Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/api-search.md Fetch the highest UID in the selected folder efficiently using GetMaxUID(), which leverages RFC-4731. This is more performant than fetching all UIDs but might not be supported by all IMAP servers. ```go func (d *Dialer) GetMaxUID() (int, error) ``` ```go maxUID, err := conn.GetMaxUID() if err != nil { log.Printf("Server may not support RFC-4731: %v", err) } ``` -------------------------------- ### Safely Count Emails Across Folders Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/architecture.md Use `GetTotalEmailCountSafe` to get the total email count while skipping problematic folders. This method returns the total count and a list of errors encountered. ```go // Unsafe - fails on first error total, _ := conn.GetTotalEmailCount() // Safe - continues despite errors total, errors, _ := conn.GetTotalEmailCountSafe() ``` -------------------------------- ### Fetching Email Details Source: https://github.com/brianleishman/go-imap/blob/master/README.md Demonstrates how to fetch email overviews (headers only) and full email content, including bodies and attachments. ```APIDOC ## Fetching Email Details ### Get Overviews (Headers Only) This method fetches only the headers of emails, making it a fast operation. ```go // Get overview (headers only, no body) - FAST overviews, err := m.GetOverviews(uids...) if err != nil { panic(err) } for uid, email := range overviews { fmt.Printf("UID %d:\n", uid) fmt.Printf(" Subject: %s\n", email.Subject) fmt.Printf(" From: %s\n", email.From) fmt.Printf(" Date: %s\n", email.Sent) fmt.Printf(" Size: %d bytes\n", email.Size) fmt.Printf(" Flags: %v\n", email.Flags) } ``` ### Get Full Emails (With Bodies) This method fetches the complete email content, including the body and attachments. It is slower than fetching overviews. ```go // Get full emails with bodies - SLOWER emails, err := m.GetEmails(uids...) if err != nil { panic(err) } for uid, email := range emails { fmt.Printf("\n=== Email UID %d ===\n", uid) fmt.Printf("Subject: %s\n", email.Subject) fmt.Printf("From: %s\n", email.From) fmt.Printf("To: %s\n", email.To) fmt.Printf("CC: %s\n", email.CC) fmt.Printf("Date Sent: %s\n", email.Sent) fmt.Printf("Date Received: %s\n", email.Received) fmt.Printf("Message-ID: %s\n", email.MessageID) fmt.Printf("Flags: %v\n", email.Flags) fmt.Printf("Size: %d bytes\n", email.Size) // Body content if len(email.Text) > 0 { fmt.Printf("Text (first 200 chars): %.200s...\n", email.Text) } if len(email.HTML) > 0 { fmt.Printf("HTML length: %d bytes\n", len(email.HTML)) } // Attachments if len(email.Attachments) > 0 { fmt.Printf("Attachments (%d):\n", len(email.Attachments)) for _, att := range email.Attachments { fmt.Printf(" - %s (%s, %d bytes)\n", att.Name, att.MimeType, len(att.Content)) } } } ``` ### Email Summary String Representation Provides a concise string representation of an email object. ```go // Using the String() method for a quick summary email := emails[245] fmt.Print(email) ``` ``` -------------------------------- ### Basic Connection with LOGIN Authentication Source: https://github.com/brianleishman/go-imap/blob/master/README.md Establishes a connection to an IMAP server using standard LOGIN authentication. Configurable timeouts and retry counts are shown. Ensure to handle potential errors during connection and defer closing the connection. ```go package main import ( "fmt" "time" imap "github.com/BrianLeishman/go-imap" ) func main() { // Optional configuration imap.Verbose = false // Enable to emit debug-level IMAP logs imap.RetryCount = 3 // Number of retries for failed commands imap.DialTimeout = 10 * time.Second imap.CommandTimeout = 30 * time.Second // For self-signed certificates (use with caution!) // imap.TLSSkipVerify = true // Connect with standard LOGIN authentication m, err := imap.New("username", "password", "mail.server.com", 993) if err != nil { panic(err) } defer m.Close() // Quick test folders, err := m.GetFolders() if err != nil { panic(err) } fmt.Printf("Connected! Found %d folders\n", len(folders)) } ``` -------------------------------- ### Optimize IMAP Performance with UID Ranges Source: https://github.com/brianleishman/go-imap/blob/master/_autodocs/quick-start.md Improve performance with large mailboxes by using GetFolderStats() to get UID ranges or by querying specific UID ranges like recent messages. ```go // Use GetFolderStats() to get UID ranges, then query specific ranges stats, _ := conn.GetFolderStats() // Or use specific UID ranges uids, _ := conn.GetUIDs("100000:*") // Only recent messages ```