Skip to main content

rusmes_core/matchers/
recipient_is_local.rs

1//! Matcher for local recipients
2
3use crate::matcher::Matcher;
4use async_trait::async_trait;
5use rusmes_proto::{Mail, MailAddress};
6
7/// Matches recipients in local domains
8pub struct RecipientIsLocalMatcher {
9    local_domains: Vec<String>,
10}
11
12impl RecipientIsLocalMatcher {
13    /// Create a new RecipientIsLocal matcher
14    pub fn new(local_domains: Vec<String>) -> Self {
15        Self { local_domains }
16    }
17}
18
19#[async_trait]
20impl Matcher for RecipientIsLocalMatcher {
21    async fn match_mail(&self, mail: &Mail) -> anyhow::Result<Vec<MailAddress>> {
22        let matched: Vec<MailAddress> = mail
23            .recipients()
24            .iter()
25            .filter(|addr| {
26                self.local_domains
27                    .iter()
28                    .any(|domain| addr.domain().as_str() == domain)
29            })
30            .cloned()
31            .collect();
32
33        Ok(matched)
34    }
35
36    fn name(&self) -> &str {
37        "RecipientIsLocal"
38    }
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44    use bytes::Bytes;
45    use rusmes_proto::{HeaderMap, MessageBody, MimeMessage};
46
47    #[tokio::test]
48    async fn test_recipient_is_local() {
49        let matcher = RecipientIsLocalMatcher::new(vec!["example.com".to_string()]);
50
51        let recipients = vec![
52            "local@example.com".parse().unwrap(),
53            "remote@other.com".parse().unwrap(),
54        ];
55
56        let message = MimeMessage::new(HeaderMap::new(), MessageBody::Small(Bytes::from("Test")));
57        let mail = Mail::new(None, recipients, message, None, None);
58
59        let matched = matcher.match_mail(&mail).await.unwrap();
60        assert_eq!(matched.len(), 1);
61        assert_eq!(matched[0].domain().as_str(), "example.com");
62    }
63}