get emails and post to webhook

This commit is contained in:
Christopher Moyer 2024-05-15 11:15:39 -04:00
parent 78c37679b1
commit 6dfdefacd9
4 changed files with 1720 additions and 0 deletions

4
.gitignore vendored
View file

@ -9,4 +9,8 @@ target/
# MSVC Windows builds of rustc generate these, which store debugging information # MSVC Windows builds of rustc generate these, which store debugging information
*.pdb *.pdb
# Rust rover
.idea
*.iml
config.toml config.toml

1548
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

13
Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "email2matrix-message-service"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
confy = "0.6.1"
imap = "2.4.1"
serde = { version = "1.0.201", features = ["derive"] }
serde_json = "1.0.117"
reqwest = { version = "0.12.4", features = ["json", "blocking"] }

155
src/main.rs Normal file
View file

@ -0,0 +1,155 @@
use std::{env, fmt};
use std::collections::HashMap;
use std::fmt::Display;
use std::net::TcpStream;
use std::path::Path;
use reqwest::blocking::Response;
use serde::{Deserialize, Serialize};
fn main() {
let args: Vec<String> = env::args().collect();
let cfg: AppConfig = confy::load_path(Path::new(&args[1])).expect("Couldn't read config");
let mut imap_session = get_imap_session(&cfg);
let message = get_emails(&mut imap_session);
match message {
Some(x) => {
let mut messages_sent_successfully = Vec::new();
for email in x {
let response = post_to_hookshot(&cfg.hookshot_url, &email.1);
match response {
Ok(x) => {
if x.status().is_success() {
messages_sent_successfully.push(email.0);
}
}
_ => {}
}
}
delete_emails(messages_sent_successfully, &mut imap_session);
},
None => println!("No emails")
}
imap_session.logout().unwrap();
}
fn get_imap_session(config: &AppConfig) -> imap::Session<TcpStream> {
let stream = TcpStream::connect(&config.imap_ip).unwrap();
let client = imap::Client::new(stream);
let mut imap_session = client.login(&config.imap_user, &config.imap_password).expect("Couldn't login");
imap_session.select("INBOX").unwrap();
return imap_session;
}
fn get_emails(imap_session: &mut imap::Session<TcpStream>) -> Option<HashMap<u32, Email>> {
let ordinals = imap_session.search("ALL")?;
if ordinals.is_empty() {
return None;
}
let messages = imap_session.fetch("1:".to_owned() + &*ordinals.iter().max().unwrap().to_string(), "(BODY[TEXT] ENVELOPE)")?;
let mut emails: HashMap<u32, Email> = HashMap::new();
if messages.is_empty() {
return None;
}
for message in messages.iter() {
let body = message.text().unwrap_or_default();
let body = std::str::from_utf8(body).unwrap_or_default().to_string();
let envelope = message.envelope().unwrap();
let subject = envelope.subject.unwrap_or("No Subject".as_bytes());
let subject = std::str::from_utf8(subject).unwrap().to_string();
let from = envelope.from.as_slice();
let from_host = from.get(0).unwrap().get(0).unwrap().host.unwrap_or_default();
let from_mailbox = from.get(0).unwrap().get(0).unwrap().mailbox.unwrap_or_default();
let from = std::str::from_utf8(from_mailbox).unwrap().to_string() + "@" + &*std::str::from_utf8(from_host).unwrap().to_string();
let email = Email {
body,
subject,
from
};
emails.insert(message.message, email);
}
// imap_session.store(format!("{}", message.message), "+FLAGS (\\Deleted)")
// .expect("Couldn't delete message");
// imap_session.expunge()?;
Some(emails)
}
fn delete_emails(ordinals: Vec<u32>, imap_session: &mut imap::Session<TcpStream>) {
for ordinal in ordinals {
imap_session.store(format!("{}", ordinal), "+FLAGS (\\Deleted)")
.expect("Couldn't delete message");
}
imap_session.expunge().unwrap();
}
fn post_to_hookshot(hookshot_url: &str, email: &Email) -> reqwest::Result<Response> {
let request: HookshotRequest = match email.subject.contains("PowerPanel") {
true => {
HookshotRequest {
username: email.from.to_string(),
text: format!("{}", email.subject)
}
}
false => {
HookshotRequest {
username: email.from.to_string(),
text: format!("{}\n\n{}", email.subject, email.body)
}
}
};
let response = reqwest::blocking::Client::new()
.post(hookshot_url)
.json(&request)
.send();
return response;
}
#[derive(Debug, Serialize, Deserialize)]
struct AppConfig {
imap_ip: String,
imap_user: String,
imap_password: String,
hookshot_url: String
}
impl Default for AppConfig {
fn default() -> Self {
panic!("Could not find config file")
}
}
#[derive(Debug)]
struct Email {
body: String,
from: String,
subject: String
}
impl Display for Email {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} : {}\n {}", self.from, self.subject, self.body)
}
}
#[derive(Debug, Serialize, Deserialize)]
struct HookshotRequest {
username: String,
text: String
}