get emails and post to webhook
This commit is contained in:
parent
78c37679b1
commit
6dfdefacd9
4 changed files with 1720 additions and 0 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -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
1548
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
13
Cargo.toml
Normal file
13
Cargo.toml
Normal 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
155
src/main.rs
Normal 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
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue