// Package filter provides message filtering configuration. // It is used to restrict which messages are processed by the answer workers. // // NOTE: IMAP Search Limitations // IMAP SEARCH (RFC 3501 §6.4.4) uses case-insensitive substring matching for // text fields. // A filter like From: "alice@example.com" would match: // - alice@example.com // - malice@example.com // - alice@example.com.evil.org // // For this reason, server-side IMAP filters should be considered // performance optimizations only, not security controls. Use the // [Filters.Senders] allowlist for exact sender matching. // // [RFC 3501 §6.4.4]: // https://datatracker.ietf.org/doc/html/rfc3501#section-6.4.4 package filter import "strings" // Filters holds message filtering configuration for IMAP searches // and sender verification. type Filters struct { // Body contains keywords that must appear in the message body. Body []string `yaml:"body"` // From filters messages by the From header field. From string `yaml:"from"` // Senders is an allowlist of email addresses permitted to receive // replies. If empty, all senders are allowed. Senders []string `yaml:"allowed_senders"` // Subject filters messages by the Subject header field. Subject string `yaml:"subject"` // To filters messages by the To header field. To string `yaml:"to"` } // MatchSender checks if the sender is in the allowed list. // Returns true if the allowlist is empty (allow all) or if the sender matches. // Comparison is case-insensitive and ignores leading/trailing whitespace. func (f *Filters) MatchSender(sender string) bool { if len(f.Senders) == 0 { return true } sender = strings.ToLower(strings.TrimSpace(sender)) for _, allowed := range f.Senders { if strings.ToLower(strings.TrimSpace(allowed)) == sender { return true } } return false }