imc-vibe/backend/internal/mail/queue.go
Christoph Haas 68285d861a Add comprehensive human-readable comments to all Go files
- Comments explain what each function does and why
- Fixed unused strconv import in queue.go
- Better documentation for SMTP email service
- Explained journalctl log parsing in logs.go
- Clarified queue operations in queue.go
2026-03-22 22:43:41 +01:00

151 lines
4.9 KiB
Go

// Package mail provides functions for interacting with the mail server system.
// Currently supports Postfix mail queue operations via postqueue/postsuper commands.
package mail
import (
"bufio" // buffered scanner for reading line-by-line
"bytes" // buffer management
"encoding/json" // JSON parsing for postqueue output
"fmt" // formatted error messages
"os/exec" // executing external commands
"regexp" // regular expressions (for parsing queue output)
"strings" // string manipulation
)
// QueueEntry represents a single email in the mail queue.
type QueueEntry struct {
ID string `json:"id"` // Queue ID (hex string)
Sender string `json:"sender"` // From address
Recipients []string `json:"recipients"` // To addresses
Size int `json:"size"` // Size in bytes
Time string `json:"time"` // Arrival time
Reason string `json:"reason"` // Why it's deferred
}
// Regular expression for parsing human-readable queue output (not currently used).
var queueLineRegex = regexp.MustCompile(`^([A-Fa-f0-9]+)\s+(\d+)\s+(\w+)\s+([A-Za-z]+\s+\d+\s+[\d:]+)\s+([^\s]+)\s+(.+)$`)
// GetQueue retrieves all emails currently in the Postfix queue.
// Returns: a list of QueueEntry objects, or an error if the command fails.
// Uses `postqueue -j` to get JSON output from Postfix.
func GetQueue() ([]QueueEntry, error) {
// Execute postqueue command with JSON output flag.
// postqueue is the Postfix queue management utility.
cmd := exec.Command("/usr/sbin/postqueue", "-j")
var out bytes.Buffer
var stderr bytes.Buffer
cmd.Stdout = &out // Capture standard output
cmd.Stderr = &stderr // Capture standard error (for debugging)
err := cmd.Run()
if err != nil {
// Return detailed error including stderr for debugging.
return nil, fmt.Errorf("/usr/sbin/postqueue -j: %v (stderr: %s)", err, stderr.String())
}
// Parse the JSON output from postqueue.
// Each line of output is a separate JSON object.
var entries []QueueEntry
scanner := bufio.NewScanner(&out) // Read line by line
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
// Skip empty lines and non-JSON lines.
if line == "" || !strings.HasPrefix(line, "{") {
continue
}
// Define the JSON structure matching postqueue's output format.
var entry struct {
QueueID string `json:"queueid"`
Sender string `json:"sender"`
Recipients []struct {
Address string `json:"address"`
} `json:"recipients"`
Size int64 `json:"size"`
Arrival string `json:"arrival_timestamp"`
Delay string `json:"delay_reason"`
}
// Parse the JSON line into our struct.
if err := json.Unmarshal([]byte(line), &entry); err != nil {
continue // Skip malformed JSON
}
// Extract recipient addresses from the nested structure.
recipients := make([]string, len(entry.Recipients))
for i, r := range entry.Recipients {
recipients[i] = r.Address
}
entries = append(entries, QueueEntry{
ID: entry.QueueID,
Sender: entry.Sender,
Recipients: recipients,
Size: int(entry.Size),
Time: entry.Arrival,
Reason: entry.Delay,
})
}
// Return empty slice instead of nil for consistent JSON output.
if entries == nil {
entries = []QueueEntry{}
}
return entries, nil
}
// RequeueMail requeues all deferred mail (attempts to resend them).
// This is a blanket operation - it requeues ALL deferred mail, not just one message.
// id: message ID (currently ignored, requeues all).
// Note: postqueue -f requeues everything, there's no per-message requeue.
func RequeueMail(id string) error {
// Execute postqueue -f to flush (requeue) all deferred mail.
cmd := exec.Command("/usr/sbin/postqueue", "-f", "-v")
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
if err := cmd.Run(); err != nil {
return err
}
return nil
}
// DeleteFromQueue deletes a specific message from the queue.
// id: the queue ID of the message to delete.
// Uses `postsuper -d <id>` to delete the message.
func DeleteFromQueue(id string) error {
// postsuper is the Postfix superuser queue management command.
// -d deletes messages by ID.
cmd := exec.Command("/usr/sbin/postsuper", "-d", id)
return cmd.Run()
}
// GetQueueCount returns the number of messages in the mail queue.
// Used for displaying queue statistics on the dashboard.
func GetQueueCount() (int, error) {
// Use JSON output to get queue count.
cmd := exec.Command("/usr/sbin/postqueue", "-j")
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return 0, err
}
// Count the number of JSON objects (messages) in the output.
count := 0
scanner := bufio.NewScanner(&out)
for scanner.Scan() {
line := scanner.Text()
// Each line of JSON output represents one message.
// Count non-empty lines that look like JSON.
if strings.TrimSpace(line) != "" && strings.HasPrefix(line, "{") {
count++
}
}
return count, nil
}