aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.rs20
1 files changed, 15 insertions, 5 deletions
diff --git a/src/main.rs b/src/main.rs
index d511632..da2e715 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,7 +12,8 @@ use tokio::net::UnixStream;
struct Config {
token: &'static str,
lmtp: &'static str,
- bind: &'static str
+ rcpt: Option<&'static str>,
+ bind: &'static str,
}
#[tokio::main]
@@ -23,6 +24,10 @@ async fn main() -> anyhow::Result<()> {
token: std::env::var("INGEST_TOKEN")?.leak(),
lmtp: std::env::var("LMTP_SOCK")?.leak(),
bind: std::env::var("LISTEN_ADDR").unwrap_or_else(|_| "127.0.0.1:8080".into()).leak(),
+ rcpt: match std::env::var("LMTP_RCPT") {
+ Ok(s) => Some(s.leak()),
+ Err(_) => None,
+ },
}));
let app = Router::new()
@@ -47,7 +52,7 @@ async fn inject(
let from = header(&headers, "x-envelope-from");
let to = header(&headers, "x-envelope-to");
- match lmtp_deliver(&cfg.lmtp, from, to, &body).await {
+ match lmtp_deliver(cfg, from, to, &body).await {
Ok(_) => StatusCode::NO_CONTENT,
Err((true, m)) => {
tracing::warn!("permanent: {m}");
@@ -73,12 +78,12 @@ fn valid_token(h: &HeaderMap, expected: &str) -> bool {
}
async fn lmtp_deliver(
- deliver_to: &str,
+ cfg: &Config,
from: &str,
to: &str,
msg: &[u8],
) -> Result<(), (bool, String)> {
- let stream = UnixStream::connect(deliver_to).await.map_err(|e| (false, e.to_string()))?;
+ let stream = UnixStream::connect(cfg.lmtp).await.map_err(|e| (false, e.to_string()))?;
let (rd, mut wr) = stream.into_split();
let mut rd = BufReader::new(rd);
let mut line = String::new();
@@ -106,15 +111,20 @@ async fn lmtp_deliver(
}};
}
+ let rcpt = cfg.rcpt.unwrap_or(to);
+
expect!("220");
io!(wr.write_all(b"LHLO alpha\r\n"));
expect!("250");
io!(wr.write_all(format!("MAIL FROM:<{from}>\r\n").as_bytes()));
expect!("250");
- io!(wr.write_all(format!("RCPT TO:<{to}>\r\n").as_bytes()));
+ io!(wr.write_all(format!("RCPT TO:<{rcpt}>\r\n").as_bytes()));
expect!("250");
io!(wr.write_all(b"DATA\r\n"));
expect!("354");
+ if cfg.rcpt.is_some() {
+ io!(wr.write_all(format!("X-Original-To: {to}\r\n").as_bytes()));
+ }
for chunk in msg.split_inclusive(|&b| b == b'\n') {
if chunk.first() == Some(&b'.') {