Improve [Client] Support Exporting Messages with various formats
- [+] feat(export): add message exporting functionality with JSON support - [+] feat(readme): update documentation to include message export feature - [+] refactor(.gitignore): change ignored files from emails.csv to test.csv and add test.json - [+] refactor(client): update message handling to use map structure instead of MessageDetails struct
This commit is contained in:
parent
9ce7f8dc5c
commit
6057f410ec
3
.gitignore
vendored
3
.gitignore
vendored
@ -30,5 +30,6 @@ tmp/
|
||||
# Project build
|
||||
bin
|
||||
|
||||
emails.csv
|
||||
test.csv
|
||||
run.go
|
||||
test.json
|
||||
|
58
README.md
58
README.md
@ -1,12 +1,14 @@
|
||||
# IMAP Client Package
|
||||
|
||||
[![Go Reference](https://pkg.go.dev/badge/git.b0zal.io/H0llyW00dzZ/imap.svg)](https://pkg.go.dev/git.b0zal.io/H0llyW00dzZ/imap) [![Go Report Card](https://goreportcard.com/badge/git.b0zal.io/H0llyW00dzZ/imap)](https://goreportcard.com/report/git.b0zal.io/H0llyW00dzZ/imap)
|
||||
|
||||
This package provides a simple interface to manage IMAP connections for single or multiple users. It allows you to connect to an IMAP server, list messages, and manage multiple user accounts.
|
||||
This package provides a simple interface to manage IMAP connections for single or multiple users. It allows you to connect to an IMAP server, list messages, export messages, and manage multiple user accounts.
|
||||
|
||||
## Features
|
||||
|
||||
- Connect and disconnect from an IMAP server
|
||||
- List messages in a specified mailbox
|
||||
- Export messages to various formats
|
||||
- Manage multiple users with separate IMAP clients
|
||||
|
||||
## Installation
|
||||
@ -60,7 +62,7 @@ func main() {
|
||||
}
|
||||
|
||||
for _, msg := range messages {
|
||||
fmt.Printf("ID: %s, From: %v, Subject: %s, Body: %s\n", msg.ID, msg.From, msg.Subject, msg.Body)
|
||||
fmt.Printf("ID: %s, From: %v, Subject: %s, Body: %s\n", msg[client.KeyID], msg[client.KeyFrom], msg[client.KeySubject], msg[client.KeyBody])
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -102,7 +104,57 @@ func main() {
|
||||
}
|
||||
|
||||
for _, msg := range messages {
|
||||
fmt.Printf("ID: %s, From: %v, Subject: %s, Body: %s\n", msg.ID, msg.From, msg.Subject, msg.Body)
|
||||
fmt.Printf("ID: %s, From: %v, Subject: %s, Body: %s\n", msg[client.KeyID], msg[client.KeyFrom], msg[client.KeySubject], msg[client.KeyBody])
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Exporting Messages
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.b0zal.io/H0llyW00dzZ/imap/client"
|
||||
"git.b0zal.io/H0llyW00dzZ/imap/export"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config := &client.Config{
|
||||
Username: "user@example.com",
|
||||
Password: "password",
|
||||
Server: "imap.example.com:993",
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
imapClient := client.NewIMAP(config)
|
||||
|
||||
err := imapClient.Connect()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to connect: %v", err)
|
||||
}
|
||||
defer imapClient.Disconnect()
|
||||
|
||||
messageConfig := client.MessageConfig{
|
||||
GrabID: true,
|
||||
GrabFrom: true,
|
||||
GrabSubject: true,
|
||||
GrabBody: true,
|
||||
}
|
||||
|
||||
file, err := os.Create("messages.json")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
exporter := &export.JSONExporter{Encoder: export.DefaultJSONEncoder}
|
||||
err = imapClient.ExportMessagesTo(file, exporter, "INBOX", 10, messageConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to export messages: %v", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
29
client/export_messages.go
Normal file
29
client/export_messages.go
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2025 H0llyW00dzZ All rights reserved.
|
||||
//
|
||||
// By accessing or using this software, you agree to be bound by the terms
|
||||
// of the License Agreement, which you can find at LICENSE files.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"git.b0zal.io/H0llyW00dzZ/imap/export"
|
||||
)
|
||||
|
||||
// ExportMessagesTo uses the provided exporter to write messages to the writer
|
||||
func (c *IMAPClient) ExportMessagesTo(writer io.Writer, exporter export.Exporter, mailbox string, numMessages uint32, config MessageConfig) error {
|
||||
if c.client == nil {
|
||||
return fmt.Errorf("client is not connected")
|
||||
}
|
||||
|
||||
// Fetch messages based on the provided MessageConfig and number of messages
|
||||
messages, err := c.ListMessages(mailbox, numMessages, config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list messages: %v", err)
|
||||
}
|
||||
|
||||
// Use the exporter to write messages
|
||||
return exporter.Export(messages, writer)
|
||||
}
|
21
client/get_multi_user.go
Normal file
21
client/get_multi_user.go
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright (c) 2025 H0llyW00dzZ All rights reserved.
|
||||
//
|
||||
// By accessing or using this software, you agree to be bound by the terms
|
||||
// of the License Agreement, which you can find at LICENSE files.
|
||||
|
||||
package client
|
||||
|
||||
import "fmt"
|
||||
|
||||
// GetClient retrieves the IMAPClient for a specific user
|
||||
func (m *MultiUserIMAP) GetClient(username string) (*IMAPClient, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
client, exists := m.clients[username]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("user not found: %s", username)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
@ -12,18 +12,19 @@ import (
|
||||
"github.com/valyala/bytebufferpool"
|
||||
)
|
||||
|
||||
// MessageDetails holds the details of an email message.
|
||||
// This struct allows the caller to access and format the message's
|
||||
// ID, sender information, subject, and body as needed.
|
||||
type MessageDetails struct {
|
||||
ID string
|
||||
From []string
|
||||
Subject string
|
||||
Body string
|
||||
}
|
||||
const (
|
||||
// KeyID is the key for the message ID
|
||||
KeyID = "id"
|
||||
// KeyFrom is the key for the sender's address
|
||||
KeyFrom = "from"
|
||||
// KeySubject is the key for the message subject
|
||||
KeySubject = "subject"
|
||||
// KeyBody is the key for the message body
|
||||
KeyBody = "body"
|
||||
)
|
||||
|
||||
// ListMessages lists the messages in the specified mailbox based on the MessageConfig
|
||||
func (c *IMAPClient) ListMessages(mailbox string, numMessages uint32, config MessageConfig) ([]MessageDetails, error) {
|
||||
func (c *IMAPClient) ListMessages(mailbox string, numMessages uint32, config MessageConfig) ([]map[string]any, error) {
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("client is not connected")
|
||||
}
|
||||
@ -52,26 +53,28 @@ func (c *IMAPClient) ListMessages(mailbox string, numMessages uint32, config Mes
|
||||
done <- c.client.Fetch(seqset, items, messages)
|
||||
}()
|
||||
|
||||
var results []MessageDetails
|
||||
var results []map[string]any
|
||||
for msg := range messages {
|
||||
details := MessageDetails{}
|
||||
details := make(map[string]any)
|
||||
|
||||
if config.GrabID {
|
||||
details.ID = msg.Envelope.MessageId
|
||||
if config.GrabID && msg.Envelope.MessageId != "" {
|
||||
details[KeyID] = msg.Envelope.MessageId
|
||||
}
|
||||
if config.GrabFrom {
|
||||
var from []string
|
||||
for _, addr := range msg.Envelope.From {
|
||||
details.From = append(details.From, addr.Address())
|
||||
from = append(from, addr.Address())
|
||||
}
|
||||
details[KeyFrom] = from
|
||||
}
|
||||
if config.GrabSubject {
|
||||
details.Subject = msg.Envelope.Subject
|
||||
if config.GrabSubject && msg.Envelope.Subject != "" {
|
||||
details[KeySubject] = msg.Envelope.Subject
|
||||
}
|
||||
if config.GrabBody {
|
||||
for _, literal := range msg.Body {
|
||||
buf := bytebufferpool.Get()
|
||||
if _, err := buf.ReadFrom(literal); err == nil {
|
||||
details.Body = buf.String()
|
||||
details[KeyBody] = buf.String()
|
||||
}
|
||||
buf.Reset() // Reset the buffer before returning it to the pool.
|
||||
bytebufferpool.Put(buf)
|
||||
@ -88,7 +91,7 @@ func (c *IMAPClient) ListMessages(mailbox string, numMessages uint32, config Mes
|
||||
}
|
||||
|
||||
// ListUserMessages lists messages for a specific user based on the MessageConfig
|
||||
func (m *MultiUserIMAP) ListUserMessages(username, mailbox string, numMessages uint32, config MessageConfig) ([]MessageDetails, error) {
|
||||
func (m *MultiUserIMAP) ListUserMessages(username, mailbox string, numMessages uint32, config MessageConfig) ([]map[string]any, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
|
15
export/exporter.go
Normal file
15
export/exporter.go
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2025 H0llyW00dzZ All rights reserved.
|
||||
//
|
||||
// By accessing or using this software, you agree to be bound by the terms
|
||||
// of the License Agreement, which you can find at LICENSE files.
|
||||
|
||||
package export
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// Exporter defines an interface for exporting messages
|
||||
type Exporter interface {
|
||||
Export(messages []map[string]any, writer io.Writer) error
|
||||
}
|
36
export/json_exporter.go
Normal file
36
export/json_exporter.go
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2025 H0llyW00dzZ All rights reserved.
|
||||
//
|
||||
// By accessing or using this software, you agree to be bound by the terms
|
||||
// of the License Agreement, which you can find at LICENSE files.
|
||||
|
||||
package export
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// JSONEncoderFunc defines a function type for custom JSON encoding
|
||||
type JSONEncoderFunc func(v any, writer io.Writer) error
|
||||
|
||||
// JSONExporter implements the Exporter interface for JSON with a custom encoder
|
||||
type JSONExporter struct {
|
||||
Encoder JSONEncoderFunc
|
||||
}
|
||||
|
||||
// Export writes messages to the writer using the custom JSON encoder
|
||||
func (e *JSONExporter) Export(messages []map[string]any, writer io.Writer) error {
|
||||
for _, msg := range messages {
|
||||
if err := e.Encoder(msg, writer); err != nil {
|
||||
return fmt.Errorf("failed to encode message to JSON: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultJSONEncoder is the default JSON encoding function using the standard library
|
||||
func DefaultJSONEncoder(v any, writer io.Writer) error {
|
||||
encoder := json.NewEncoder(writer)
|
||||
return encoder.Encode(v)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user