1use crate::listeners::{
7 ConnectionLimitsConfig, ImapServerConfig, JmapServerConfig, RateLimitConfig,
8};
9use crate::parse::{
10 default_idle_timeout, default_max_connections_per_ip, default_max_total_connections,
11 default_reaper_interval,
12};
13use crate::runtime::{LoggingConfig, MetricsConfig, OtlpProtocol, QueueConfig, TracingConfig};
14use crate::ServerConfig;
15
16impl ServerConfig {
17 pub fn apply_env_overrides(&mut self) {
63 if let Ok(val) = std::env::var("RUSMES_DOMAIN") {
65 self.domain = val;
66 }
67 if let Ok(val) = std::env::var("RUSMES_POSTMASTER") {
68 self.postmaster = val;
69 }
70
71 if let Ok(val) = std::env::var("RUSMES_SMTP_HOST") {
73 self.smtp.host = val;
74 }
75 if let Ok(val) = std::env::var("RUSMES_SMTP_PORT") {
76 if let Ok(port) = val.parse::<u16>() {
77 self.smtp.port = port;
78 }
79 }
80 if let Ok(val) = std::env::var("RUSMES_SMTP_TLS_PORT") {
81 if let Ok(port) = val.parse::<u16>() {
82 self.smtp.tls_port = Some(port);
83 }
84 }
85 if let Ok(val) = std::env::var("RUSMES_SMTP_MAX_MESSAGE_SIZE") {
86 self.smtp.max_message_size = val;
87 }
88 if let Ok(val) = std::env::var("RUSMES_SMTP_REQUIRE_AUTH") {
89 if let Ok(b) = val.parse::<bool>() {
90 self.smtp.require_auth = b;
91 }
92 }
93 if let Ok(val) = std::env::var("RUSMES_SMTP_ENABLE_STARTTLS") {
94 if let Ok(b) = val.parse::<bool>() {
95 self.smtp.enable_starttls = b;
96 }
97 }
98
99 let has_rate_limit_max =
101 std::env::var("RUSMES_SMTP_RATE_LIMIT_MAX_MESSAGES_PER_HOUR").is_ok();
102 let has_rate_limit_window = std::env::var("RUSMES_SMTP_RATE_LIMIT_WINDOW_DURATION").is_ok();
103 let has_rate_limit_max_conn =
104 std::env::var("RUSMES_SMTP_RATE_LIMIT_MAX_CONNECTIONS_PER_IP").is_ok();
105
106 if has_rate_limit_max || has_rate_limit_window || has_rate_limit_max_conn {
107 if self.smtp.rate_limit.is_none() {
109 self.smtp.rate_limit = Some(RateLimitConfig {
110 max_connections_per_ip: 10,
111 max_messages_per_hour: 100,
112 window_duration: "1h".to_string(),
113 });
114 }
115
116 if let Some(ref mut rate_limit) = self.smtp.rate_limit {
117 if let Ok(val) = std::env::var("RUSMES_SMTP_RATE_LIMIT_MAX_CONNECTIONS_PER_IP") {
118 if let Ok(n) = val.parse::<usize>() {
119 rate_limit.max_connections_per_ip = n;
120 }
121 }
122 if let Ok(val) = std::env::var("RUSMES_SMTP_RATE_LIMIT_MAX_MESSAGES_PER_HOUR") {
123 if let Ok(n) = val.parse::<u32>() {
124 rate_limit.max_messages_per_hour = n;
125 }
126 }
127 if let Ok(val) = std::env::var("RUSMES_SMTP_RATE_LIMIT_WINDOW_DURATION") {
128 rate_limit.window_duration = val;
129 }
130 }
131 }
132
133 if let Ok(val) = std::env::var("RUSMES_IMAP_HOST") {
135 if self.imap.is_none() {
136 self.imap = Some(ImapServerConfig {
137 host: "0.0.0.0".to_string(),
138 port: 143,
139 tls_port: None,
140 });
141 }
142 if let Some(ref mut imap) = self.imap {
143 imap.host = val;
144 }
145 }
146 if let Ok(val) = std::env::var("RUSMES_IMAP_PORT") {
147 if let Ok(port) = val.parse::<u16>() {
148 if self.imap.is_none() {
149 self.imap = Some(ImapServerConfig {
150 host: "0.0.0.0".to_string(),
151 port,
152 tls_port: None,
153 });
154 } else if let Some(ref mut imap) = self.imap {
155 imap.port = port;
156 }
157 }
158 }
159 if let Ok(val) = std::env::var("RUSMES_IMAP_TLS_PORT") {
160 if let Ok(port) = val.parse::<u16>() {
161 if self.imap.is_none() {
162 self.imap = Some(ImapServerConfig {
163 host: "0.0.0.0".to_string(),
164 port: 143,
165 tls_port: Some(port),
166 });
167 } else if let Some(ref mut imap) = self.imap {
168 imap.tls_port = Some(port);
169 }
170 }
171 }
172
173 if let Ok(val) = std::env::var("RUSMES_JMAP_HOST") {
175 if self.jmap.is_none() {
176 self.jmap = Some(JmapServerConfig {
177 host: "0.0.0.0".to_string(),
178 port: 8080,
179 base_url: "http://localhost:8080".to_string(),
180 push: None,
181 });
182 }
183 if let Some(ref mut jmap) = self.jmap {
184 jmap.host = val;
185 }
186 }
187 if let Ok(val) = std::env::var("RUSMES_JMAP_PORT") {
188 if let Ok(port) = val.parse::<u16>() {
189 if self.jmap.is_none() {
190 self.jmap = Some(JmapServerConfig {
191 host: "0.0.0.0".to_string(),
192 port,
193 base_url: "http://localhost:8080".to_string(),
194 push: None,
195 });
196 } else if let Some(ref mut jmap) = self.jmap {
197 jmap.port = port;
198 }
199 }
200 }
201 if let Ok(val) = std::env::var("RUSMES_JMAP_BASE_URL") {
202 if self.jmap.is_none() {
203 self.jmap = Some(JmapServerConfig {
204 host: "0.0.0.0".to_string(),
205 port: 8080,
206 base_url: val,
207 push: None,
208 });
209 } else if let Some(ref mut jmap) = self.jmap {
210 jmap.base_url = val;
211 }
212 }
213
214 if let Ok(val) = std::env::var("RUSMES_STORAGE_PATH") {
216 if let crate::StorageConfig::Filesystem { ref mut path } = self.storage {
217 *path = val;
218 }
219 }
220
221 if let Ok(val) = std::env::var("RUSMES_LOG_LEVEL") {
223 if self.logging.is_none() {
224 self.logging = Some(LoggingConfig {
225 level: val,
226 format: "text".to_string(),
227 output: "stdout".to_string(),
228 file: None,
229 });
230 } else if let Some(ref mut logging) = self.logging {
231 logging.level = val;
232 }
233 }
234 if let Ok(val) = std::env::var("RUSMES_LOG_FORMAT") {
235 if self.logging.is_none() {
236 self.logging = Some(LoggingConfig {
237 level: "info".to_string(),
238 format: val,
239 output: "stdout".to_string(),
240 file: None,
241 });
242 } else if let Some(ref mut logging) = self.logging {
243 logging.format = val;
244 }
245 }
246 if let Ok(val) = std::env::var("RUSMES_LOG_OUTPUT") {
247 if self.logging.is_none() {
248 self.logging = Some(LoggingConfig {
249 level: "info".to_string(),
250 format: "text".to_string(),
251 output: val,
252 file: None,
253 });
254 } else if let Some(ref mut logging) = self.logging {
255 logging.output = val;
256 }
257 }
258
259 if let Ok(val) = std::env::var("RUSMES_QUEUE_INITIAL_DELAY") {
261 if self.queue.is_none() {
262 self.queue = Some(QueueConfig {
263 initial_delay: val,
264 max_delay: "3600s".to_string(),
265 backoff_multiplier: 2.0,
266 max_attempts: 5,
267 worker_threads: 4,
268 batch_size: 100,
269 });
270 } else if let Some(ref mut queue) = self.queue {
271 queue.initial_delay = val;
272 }
273 }
274 if let Ok(val) = std::env::var("RUSMES_QUEUE_MAX_DELAY") {
275 if self.queue.is_none() {
276 self.queue = Some(QueueConfig {
277 initial_delay: "60s".to_string(),
278 max_delay: val,
279 backoff_multiplier: 2.0,
280 max_attempts: 5,
281 worker_threads: 4,
282 batch_size: 100,
283 });
284 } else if let Some(ref mut queue) = self.queue {
285 queue.max_delay = val;
286 }
287 }
288 if let Ok(val) = std::env::var("RUSMES_QUEUE_BACKOFF_MULTIPLIER") {
289 if let Ok(multiplier) = val.parse::<f64>() {
290 if self.queue.is_none() {
291 self.queue = Some(QueueConfig {
292 initial_delay: "60s".to_string(),
293 max_delay: "3600s".to_string(),
294 backoff_multiplier: multiplier,
295 max_attempts: 5,
296 worker_threads: 4,
297 batch_size: 100,
298 });
299 } else if let Some(ref mut queue) = self.queue {
300 queue.backoff_multiplier = multiplier;
301 }
302 }
303 }
304 if let Ok(val) = std::env::var("RUSMES_QUEUE_MAX_ATTEMPTS") {
305 if let Ok(attempts) = val.parse::<u32>() {
306 if self.queue.is_none() {
307 self.queue = Some(QueueConfig {
308 initial_delay: "60s".to_string(),
309 max_delay: "3600s".to_string(),
310 backoff_multiplier: 2.0,
311 max_attempts: attempts,
312 worker_threads: 4,
313 batch_size: 100,
314 });
315 } else if let Some(ref mut queue) = self.queue {
316 queue.max_attempts = attempts;
317 }
318 }
319 }
320 if let Ok(val) = std::env::var("RUSMES_QUEUE_WORKER_THREADS") {
321 if let Ok(threads) = val.parse::<usize>() {
322 if self.queue.is_none() {
323 self.queue = Some(QueueConfig {
324 initial_delay: "60s".to_string(),
325 max_delay: "3600s".to_string(),
326 backoff_multiplier: 2.0,
327 max_attempts: 5,
328 worker_threads: threads,
329 batch_size: 100,
330 });
331 } else if let Some(ref mut queue) = self.queue {
332 queue.worker_threads = threads;
333 }
334 }
335 }
336 if let Ok(val) = std::env::var("RUSMES_QUEUE_BATCH_SIZE") {
337 if let Ok(batch_size) = val.parse::<usize>() {
338 if self.queue.is_none() {
339 self.queue = Some(QueueConfig {
340 initial_delay: "60s".to_string(),
341 max_delay: "3600s".to_string(),
342 backoff_multiplier: 2.0,
343 max_attempts: 5,
344 worker_threads: 4,
345 batch_size,
346 });
347 } else if let Some(ref mut queue) = self.queue {
348 queue.batch_size = batch_size;
349 }
350 }
351 }
352
353 if let Ok(val) = std::env::var("RUSMES_METRICS_ENABLED") {
355 if let Ok(enabled) = val.parse::<bool>() {
356 if self.metrics.is_none() {
357 self.metrics = Some(MetricsConfig {
358 enabled,
359 bind_address: "0.0.0.0:9090".to_string(),
360 path: "/metrics".to_string(),
361 basic_auth: None,
362 });
363 } else if let Some(ref mut metrics) = self.metrics {
364 metrics.enabled = enabled;
365 }
366 }
367 }
368 if let Ok(val) = std::env::var("RUSMES_METRICS_BIND_ADDRESS") {
369 if self.metrics.is_none() {
370 self.metrics = Some(MetricsConfig {
371 enabled: true,
372 bind_address: val,
373 path: "/metrics".to_string(),
374 basic_auth: None,
375 });
376 } else if let Some(ref mut metrics) = self.metrics {
377 metrics.bind_address = val;
378 }
379 }
380 if let Ok(val) = std::env::var("RUSMES_METRICS_PATH") {
381 if self.metrics.is_none() {
382 self.metrics = Some(MetricsConfig {
383 enabled: true,
384 bind_address: "0.0.0.0:9090".to_string(),
385 path: val,
386 basic_auth: None,
387 });
388 } else if let Some(ref mut metrics) = self.metrics {
389 metrics.path = val;
390 }
391 }
392
393 if let Ok(val) = std::env::var("RUSMES_TRACING_ENABLED") {
395 if let Ok(enabled) = val.parse::<bool>() {
396 if self.tracing.is_none() {
397 self.tracing = Some(TracingConfig {
398 enabled,
399 ..Default::default()
400 });
401 } else if let Some(ref mut tracing) = self.tracing {
402 tracing.enabled = enabled;
403 }
404 }
405 }
406 if let Ok(val) = std::env::var("RUSMES_TRACING_ENDPOINT") {
407 if self.tracing.is_none() {
408 self.tracing = Some(TracingConfig {
409 enabled: true,
410 endpoint: val,
411 ..Default::default()
412 });
413 } else if let Some(ref mut tracing) = self.tracing {
414 tracing.endpoint = val;
415 }
416 }
417 if let Ok(val) = std::env::var("RUSMES_TRACING_PROTOCOL") {
418 let protocol = match val.to_lowercase().as_str() {
419 "grpc" => OtlpProtocol::Grpc,
420 "http" => OtlpProtocol::Http,
421 _ => OtlpProtocol::Grpc,
422 };
423 if self.tracing.is_none() {
424 self.tracing = Some(TracingConfig {
425 enabled: true,
426 protocol,
427 ..Default::default()
428 });
429 } else if let Some(ref mut tracing) = self.tracing {
430 tracing.protocol = protocol;
431 }
432 }
433 if let Ok(val) = std::env::var("RUSMES_TRACING_SERVICE_NAME") {
434 if self.tracing.is_none() {
435 self.tracing = Some(TracingConfig {
436 enabled: true,
437 service_name: val,
438 ..Default::default()
439 });
440 } else if let Some(ref mut tracing) = self.tracing {
441 tracing.service_name = val;
442 }
443 }
444 if let Ok(val) = std::env::var("RUSMES_TRACING_SAMPLE_RATIO") {
445 if let Ok(ratio) = val.parse::<f64>() {
446 if self.tracing.is_none() {
447 self.tracing = Some(TracingConfig {
448 enabled: true,
449 sample_ratio: ratio,
450 ..Default::default()
451 });
452 } else if let Some(ref mut tracing) = self.tracing {
453 tracing.sample_ratio = ratio;
454 }
455 }
456 }
457
458 if let Ok(val) = std::env::var("RUSMES_CONNECTION_LIMITS_MAX_CONNECTIONS_PER_IP") {
460 if let Ok(max) = val.parse::<usize>() {
461 if self.connection_limits.is_none() {
462 self.connection_limits = Some(ConnectionLimitsConfig {
463 max_connections_per_ip: max,
464 max_total_connections: default_max_total_connections(),
465 idle_timeout: default_idle_timeout(),
466 reaper_interval: default_reaper_interval(),
467 });
468 } else if let Some(ref mut limits) = self.connection_limits {
469 limits.max_connections_per_ip = max;
470 }
471 }
472 }
473 if let Ok(val) = std::env::var("RUSMES_CONNECTION_LIMITS_MAX_TOTAL_CONNECTIONS") {
474 if let Ok(max) = val.parse::<usize>() {
475 if self.connection_limits.is_none() {
476 self.connection_limits = Some(ConnectionLimitsConfig {
477 max_connections_per_ip: default_max_connections_per_ip(),
478 max_total_connections: max,
479 idle_timeout: default_idle_timeout(),
480 reaper_interval: default_reaper_interval(),
481 });
482 } else if let Some(ref mut limits) = self.connection_limits {
483 limits.max_total_connections = max;
484 }
485 }
486 }
487 if let Ok(val) = std::env::var("RUSMES_CONNECTION_LIMITS_IDLE_TIMEOUT") {
488 if self.connection_limits.is_none() {
489 self.connection_limits = Some(ConnectionLimitsConfig {
490 max_connections_per_ip: default_max_connections_per_ip(),
491 max_total_connections: default_max_total_connections(),
492 idle_timeout: val,
493 reaper_interval: default_reaper_interval(),
494 });
495 } else if let Some(ref mut limits) = self.connection_limits {
496 limits.idle_timeout = val;
497 }
498 }
499 if let Ok(val) = std::env::var("RUSMES_CONNECTION_LIMITS_REAPER_INTERVAL") {
500 if self.connection_limits.is_none() {
501 self.connection_limits = Some(ConnectionLimitsConfig {
502 max_connections_per_ip: default_max_connections_per_ip(),
503 max_total_connections: default_max_total_connections(),
504 idle_timeout: default_idle_timeout(),
505 reaper_interval: val,
506 });
507 } else if let Some(ref mut limits) = self.connection_limits {
508 limits.reaper_interval = val;
509 }
510 }
511 }
512}