feat(channels): wire up email channel (IMAP/SMTP) into config and registration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Argenis 2026-02-15 10:58:30 -05:00 committed by GitHub
parent efe7ae53ce
commit ced4d70814
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 48 additions and 162 deletions

View file

@ -11,6 +11,7 @@ pub mod whatsapp;
pub use cli::CliChannel;
pub use discord::DiscordChannel;
pub use email_channel::EmailChannel;
pub use imessage::IMessageChannel;
pub use irc::IrcChannel;
pub use matrix::MatrixChannel;
@ -256,6 +257,7 @@ pub fn handle_command(command: crate::ChannelCommands, config: &Config) -> Resul
("iMessage", config.channels_config.imessage.is_some()),
("Matrix", config.channels_config.matrix.is_some()),
("WhatsApp", config.channels_config.whatsapp.is_some()),
("Email", config.channels_config.email.is_some()),
("IRC", config.channels_config.irc.is_some()),
] {
println!(" {} {name}", if configured { "" } else { "" });
@ -363,6 +365,10 @@ pub async fn doctor_channels(config: Config) -> Result<()> {
));
}
if let Some(ref email_cfg) = config.channels_config.email {
channels.push(("Email", Arc::new(EmailChannel::new(email_cfg.clone()))));
}
if let Some(ref irc) = config.channels_config.irc {
channels.push((
"IRC",
@ -548,6 +554,10 @@ pub async fn start_channels(config: Config) -> Result<()> {
)));
}
if let Some(ref email_cfg) = config.channels_config.email {
channels.push(Arc::new(EmailChannel::new(email_cfg.clone())));
}
if let Some(ref irc) = config.channels_config.irc {
channels.push(Arc::new(IrcChannel::new(
irc.server.clone(),

View file

@ -541,6 +541,7 @@ pub struct ChannelsConfig {
pub imessage: Option<IMessageConfig>,
pub matrix: Option<MatrixConfig>,
pub whatsapp: Option<WhatsAppConfig>,
pub email: Option<crate::channels::email_channel::EmailConfig>,
pub irc: Option<IrcConfig>,
}
@ -555,6 +556,7 @@ impl Default for ChannelsConfig {
imessage: None,
matrix: None,
whatsapp: None,
email: None,
irc: None,
}
}
@ -889,6 +891,7 @@ mod tests {
imessage: None,
matrix: None,
whatsapp: None,
email: None,
irc: None,
},
memory: MemoryConfig::default(),
@ -1102,6 +1105,7 @@ default_temperature = 0.7
allowed_users: vec!["@u:m".into()],
}),
whatsapp: None,
email: None,
irc: None,
};
let toml_str = toml::to_string_pretty(&c).unwrap();
@ -1259,6 +1263,7 @@ channel_id = "C123"
app_secret: None,
allowed_numbers: vec!["+1".into()],
}),
email: None,
irc: None,
};
let toml_str = toml::to_string_pretty(&c).unwrap();

View file

@ -210,6 +210,8 @@ fn has_supervised_channels(config: &Config) -> bool {
|| config.channels_config.slack.is_some()
|| config.channels_config.imessage.is_some()
|| config.channels_config.matrix.is_some()
|| config.channels_config.whatsapp.is_some()
|| config.channels_config.email.is_some()
}
#[cfg(test)]

View file

@ -129,7 +129,8 @@ pub fn run_wizard() -> Result<Config> {
|| config.channels_config.discord.is_some()
|| config.channels_config.slack.is_some()
|| config.channels_config.imessage.is_some()
|| config.channels_config.matrix.is_some();
|| config.channels_config.matrix.is_some()
|| config.channels_config.email.is_some();
if has_channels && config.api_key.is_some() {
let launch: bool = Confirm::new()
@ -184,7 +185,8 @@ pub fn run_channels_repair_wizard() -> Result<Config> {
|| config.channels_config.discord.is_some()
|| config.channels_config.slack.is_some()
|| config.channels_config.imessage.is_some()
|| config.channels_config.matrix.is_some();
|| config.channels_config.matrix.is_some()
|| config.channels_config.email.is_some();
if has_channels && config.api_key.is_some() {
let launch: bool = Confirm::new()
@ -1114,6 +1116,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
imessage: None,
matrix: None,
whatsapp: None,
email: None,
irc: None,
};
@ -1891,6 +1894,9 @@ fn setup_channels() -> Result<ChannelsConfig> {
if config.whatsapp.is_some() {
active.push("WhatsApp");
}
if config.email.is_some() {
active.push("Email");
}
if config.irc.is_some() {
active.push("IRC");
}
@ -2346,7 +2352,8 @@ fn print_summary(config: &Config) {
|| config.channels_config.discord.is_some()
|| config.channels_config.slack.is_some()
|| config.channels_config.imessage.is_some()
|| config.channels_config.matrix.is_some();
|| config.channels_config.matrix.is_some()
|| config.channels_config.email.is_some();
println!();
println!(
@ -2408,6 +2415,9 @@ fn print_summary(config: &Config) {
if config.channels_config.matrix.is_some() {
channels.push("Matrix");
}
if config.channels_config.email.is_some() {
channels.push("Email");
}
if config.channels_config.webhook.is_some() {
channels.push("Webhook");
}

View file

@ -50,10 +50,7 @@ impl AnthropicProvider {
.map(str::trim)
.filter(|k| !k.is_empty())
.map(ToString::to_string),
<<<<<<< HEAD
=======
base_url,
>>>>>>> origin/main
client: Client::builder()
.timeout(std::time::Duration::from_secs(120))
.connect_timeout(std::time::Duration::from_secs(10))
@ -95,11 +92,7 @@ impl Provider for AnthropicProvider {
let mut request = self
.client
<<<<<<< HEAD
.post("https://api.anthropic.com/v1/messages")
=======
.post(format!("{}/v1/messages", self.base_url))
>>>>>>> origin/main
.header("anthropic-version", "2023-06-01")
.header("content-type", "application/json")
.json(&request);
@ -136,20 +129,14 @@ mod tests {
let p = AnthropicProvider::new(Some("sk-ant-test123"));
assert!(p.credential.is_some());
assert_eq!(p.credential.as_deref(), Some("sk-ant-test123"));
<<<<<<< HEAD
=======
assert_eq!(p.base_url, "https://api.anthropic.com");
>>>>>>> origin/main
}
#[test]
fn creates_without_key() {
let p = AnthropicProvider::new(None);
assert!(p.credential.is_none());
<<<<<<< HEAD
=======
assert_eq!(p.base_url, "https://api.anthropic.com");
>>>>>>> origin/main
}
#[test]
@ -163,8 +150,6 @@ mod tests {
let p = AnthropicProvider::new(Some(" sk-ant-test123 "));
assert!(p.credential.is_some());
assert_eq!(p.credential.as_deref(), Some("sk-ant-test123"));
<<<<<<< HEAD
=======
}
#[test]
@ -184,7 +169,6 @@ mod tests {
fn default_base_url_when_none_provided() {
let p = AnthropicProvider::with_base_url(None, None);
assert_eq!(p.base_url, "https://api.anthropic.com");
>>>>>>> origin/main
}
#[tokio::test]