Index: src/lib.rs ================================================================== --- src/lib.rs +++ src/lib.rs @@ -37,22 +37,26 @@ /// Set configuration file location #[arg(short, long, default_value = "smtp2tg.toml")] config: String, } -/// Main asynchronous entry point for the application. +/// Main asynchronous entry point for the application. Runs the gateway using +/// the configuration selected on the command line. /// -/// Parses command-line arguments, loads configuration, and starts the SMTP -/// server. +/// The configuration file must use owner-only permissions. Once configured, +/// the SMTP server runs until it stops or encounters an error. /// /// # Errors -/// Returns an error if configuration is invalid, files are inaccessible, or -/// server fails to start. +/// Returns an error if the configuration file is missing, inaccessible, +/// insecure, malformed, or contains invalid required settings. +/// +/// # Panics +/// Panics if configuring or serving the SMTP server fails. pub async fn async_main () -> Result<()> { let args = Args::parse(); let config_file = Path::new(&args.config); - if !config_file.exists() { + if !config_file.try_exists().stack()? { bail!("Configuration file not found: {config_file:?}\n\ Hint: Ensure the file exists and the path is correct."); }; { let meta = metadata(config_file).await.stack()?; @@ -74,11 +78,11 @@ .add_source(config::File::from(config_file)) .build() .with_context(|| format!( "Failed to parse configuration file: {config_file:?}\n\ Check syntax against smtp2tg.toml.example.\n\ - Common issues: missing quotes, trailing commas, or invalid types." + Common issues: missing quotes, trailing commas in inline tables, or invalid types." ))?; let listen_on = settings.get_string("listen_on").stack()?; let server_name = settings.get_string("hostname").stack()?; let core = MailServer::new(settings)?; Index: src/mail.rs ================================================================== --- src/mail.rs +++ src/mail.rs @@ -68,11 +68,10 @@ /// # Arguments /// * `settings` - Parsed application configuration. /// /// # Errors /// Returns an error if required configuration values are missing or invalid. - /// server fails to start. pub fn new (settings: config::Config) -> Result { let api_key = settings.get_string("api_key") .context("[smtp2tg.toml] missing \"api_key\" parameter.\n")?; let mut recipients = HashMap::new(); for (name, value) in settings.get_table("recipients") Index: src/telegram.rs ================================================================== --- src/telegram.rs +++ src/telegram.rs @@ -109,11 +109,12 @@ /// * `to` - Target chat ID. /// * `media` - List of attachments, non-empty. /// * `msg` - Message text (supports HTML formatting). /// /// # Returns - /// * `Result<()>` - Success or error. + /// * `Result<()>` - fails if `media` is empty, problems forming media + /// group, request fails. pub async fn sendgroup (&self, to: &ChatPeerId, media: Vec, msg: &str) -> Result<()> { if media.len() > 1 { let mut attach = vec![]; let mut pos = media.len(); for file in media {