### Install Example Configuration Files Source: https://docs.kumomta.com/userguide/installation/source?q= Installs example Lua policy configuration files. These can be used as a starting point or replaced with custom configurations. ```bash $ sudo install -Dm644 assets/init.lua -T /opt/kumomta/etc/policy/init.lua $ sudo install -Dm644 assets/tsa_init.lua -T /opt/kumomta/etc/policy/tsa_init.lua ``` -------------------------------- ### Install Example Configuration Files Source: https://docs.kumomta.com/userguide/installation/source Installs example Lua configuration files for KumoMTA's policy. These can serve as a starting point for your own custom configurations. ```bash sudo install -Dm644 assets/init.lua -T /opt/kumomta/etc/policy/init.lua sudo install -Dm644 assets/tsa_init.lua -T /opt/kumomta/etc/policy/tsa_init.lua ``` -------------------------------- ### Install Prometheus Source: https://docs.kumomta.com/userguide/integrations/prometheus Download and extract the Prometheus binary. This example installs version 2.47.2 on localhost. ```bash $ cd $ wget https://github.com/prometheus/prometheus/releases/download/v2.47.2/prometheus-2.47.2.linux-amd64.tar.gz $ tar xvf prometheus-*.*-amd64.tar.gz cd prometheus-2.47.2.linux-amd64/ ``` -------------------------------- ### Start Monitor Function Signature Source: https://docs.kumomta.com/rustapi/config/epoch/fn.start_monitor.html This is the function signature for starting the monitor. No specific setup or constraints are detailed here. ```rust pub fn start_monitor() ``` -------------------------------- ### Start and Enable KumoMTA Service Source: https://docs.kumomta.com/tutorial/quickstart?q= Starts the KumoMTA service and enables it to start automatically on system boot. Use this if the service does not start by default. ```bash sudo systemctl start kumomta sudo systemctl enable kumomta ``` -------------------------------- ### start Method Source: https://docs.kumomta.com/rustapi/kumo_server_common/http_server/struct.HttpListenerParams.html?search=std%3A%3Avec Starts an HTTP listener with the given parameters and router. ```APIDOC ## Method: HttpListenerParams::start ### Description Starts an HTTP listener with the provided `RouterAndDocs` and an optional runtime handle. This method configures and launches the server based on the `HttpListenerParams`. ### Signature `pub async fn start(self, router_and_docs: RouterAndDocs, runtime: Option) -> Result<()>` ### Parameters * `self`: `HttpListenerParams` - The configuration for the HTTP listener. * `router_and_docs`: `RouterAndDocs` - The router and documentation handler for incoming requests. * `runtime`: `Option` - An optional runtime handle for managing the server's execution context. ### Returns * `Result<()>` - Returns `Ok(())` on successful startup, or an error if the listener fails to start. ``` -------------------------------- ### Start KumoMTA Service Source: https://docs.kumomta.com/userguide/installation/linux?q= Starts the KumoMTA service using systemd. This command is used after installation to get the service running. ```bash $ sudo systemctl start kumomta ``` -------------------------------- ### StartConfig::run Method Source: https://docs.kumomta.com/rustapi/kumo_server_common/start/struct.StartConfig.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Asynchronously runs the Kumo server with provided initialization and shutdown futures. This is the main entry point for starting the server with a given configuration. ```APIDOC ## impl StartConfig<'_> ### pub async fn run( self, init_future: INIT, shutdown_future: FINI, ) -> Result<()> #### Type Parameters * `INIT`: A future that resolves to a `Result<()>` and is `Send + 'static`. * `FINI`: A future that resolves to `()` and is `Send + 'static`. #### Parameters * `self`: The `StartConfig` instance. * `init_future`: The future to execute for initialization. * `shutdown_future`: The future to execute for shutdown. ``` -------------------------------- ### Example: S3 GET request Source: https://docs.kumomta.com/reference/kumo.crypto/aws_sign_v4 Demonstrates how to sign an S3 GET request and then make the request using the computed signature. ```APIDOC ## S3 GET request Example ### Description This example shows how to use `kumo.crypto.aws_sign_v4` to generate the necessary headers for an S3 GET request and then use those headers in an `http.request`. ### Code ```lua local kumo = require 'kumo' local result = kumo.crypto.aws_sign_v4 { access_key = { key_data = 'AKIAIOSFODNN7EXAMPLE', }, secret_key = { key_data = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', }, region = 'us-east-1', service = 's3', method = 'GET', uri = '/my-bucket/my-object.txt', query_params = {}, headers = { host = 'my-bucket.s3.amazonaws.com', }, payload = '', } http.request { url = 'https://my-bucket.s3.amazonaws.com/my-object.txt', method = 'GET', headers = { ['Authorization'] = result.authorization, ['X-Amz-Date'] = result.timestamp, ['Host'] = 'my-bucket.s3.amazonaws.com', }, } ``` ``` -------------------------------- ### Configure Queues with Tenant and Campaign Headers (TOML) Source: https://docs.kumomta.com/tutorial/configuring_kumomta?q= Configure queue settings, including scheduling, tenant, and campaign headers, using TOML format. This example sets up default tenants and specific queue configurations. ```toml scheduling_header = "X-Schedule" tenant_header = "X-Tenant" remove_tenant_header = true campaign_header = "X-Campaign" remove_campaign_header = true default_tenant = "default-tenant" [tenant.'default-tenant'] egres_pool = 'default' [tenant.'mytenant'] egres_pool = 'pool-1' max_age = '10 hours' [queue.'gmail.com'] max_age = '22 hours' retry_interval = '17 mins' ``` -------------------------------- ### Build an HTTP Client and Make a GET Request Source: https://docs.kumomta.com/reference/kumo.http/build_client?q= Demonstrates how to build a basic HTTP client using default parameters and then perform a GET request to a specified URL. It also shows how to access the response status code, reason, headers, and body. ```lua local response = kumo.http.build_client({}):get('https://example.com/'):send() print(response:status_code(), response:status_reason()) for k, v in pairs(response:headers()) do print('Header', k, v) end print(response:text()) ``` -------------------------------- ### ARC Example 2 Verification Test Source: https://docs.kumomta.com/rustapi/src/kumo_dkim/arc.rs.html?search=u32+-%3E+bool Tests the verification of the second example ARC email. This test setup is similar to example 1, using a parsed email and a configured test resolver. ```rust #[tokio::test] async fn test_parse_example_2() { let email = ParsedEmail::parse(EXAMPLE_MESSAGE_2.replace(' ', "\r\n")).unwrap(); let resolver = TestResolver::default().with_txt(FM3_ZONE_NAME, FM3_ZONE_TXT); ``` -------------------------------- ### Configure Queues with Tenant and Campaign Headers (JSON) Source: https://docs.kumomta.com/tutorial/configuring_kumomta?q= Configure queue settings, including scheduling, tenant, and campaign headers, using JSON format. This example sets up default tenants and specific queue configurations. ```json { "scheduling_header": "X-Schedule", "tenant_header": "X-Tenant", "remove_tenant_header": true, "campaign_header": "X-Campaign", "remove_campaign_header": true, "default_tenant": "default-tenant", "tenant": { "default-tenant": { "egress_pool": "default" }, "mytenant": { "egress_pool": "pool-1", "max_age": "10 hours" } }, "queue": { "gmail.com": { "max_age": "22 hours", "retry_interval": "17 mins" } } } ``` -------------------------------- ### Install Caching Name Server (BIND) Source: https://docs.kumomta.com/userguide/installation/system_prep?q= Install BIND (or bind9) and start the named service. A caching name server is critical for high-performance mail engines. ```bash sudo apt install bind9 -y sudo systemctl start named ``` -------------------------------- ### Create and Use HTTP Client Source: https://docs.kumomta.com/rustapi/src/mod_http/lib.rs.html Demonstrates how to create an HTTP client and use its methods like 'get', 'post', and 'put' to initiate requests. The client can be closed to release resources. ```rust impl LuaUserData for ClientWrapper { fn add_methods>(methods: &mut M) { methods.add_method("get", |_, this, url: String| { let builder = this.get_client()?.get(url); Ok(RequestWrapper::new(builder)) }); methods.add_method("post", |_, this, url: String| { let builder = this.get_client()?.post(url); Ok(RequestWrapper::new(builder)) }); methods.add_method("put", |_, this, url: String| { let builder = this.get_client()?.put(url); Ok(RequestWrapper::new(builder)) }); methods.add_method("close", |_, this, _: ()| { this.client.lock().unwrap().take(); Ok(()) }); } } ``` -------------------------------- ### MTA-STS Policy Example Source: https://docs.kumomta.com/reference/kumo/make_egress_path/enable_mta_sts?q= This is an example of an MTA-STS policy file as returned by a GET request to the .well-known/mta-sts.txt endpoint. It defines the policy mode and MX hosts for a domain. ```text version: STSv1 mode: enforce mx: gmail-smtp-in.l.google.com mx: *.gmail-smtp-in.l.google.com max_age: 86400 ``` -------------------------------- ### Define wildcard keys in a domain map Source: https://docs.kumomta.com/reference/kumo.domain_map/new?q= Demonstrates how to use wildcard keys like '*.example.com' to match multiple domain names. Explicitly set keys take precedence over wildcards. ```lua local dmap = kumo.domain_map.new() dmap['*.example.com'] = 'wildcard' -- An exact lookup for example.com won't match the wildcard assert(dmap['example.com'] == nil) -- but any nodes "below" that will match the wildcard entry: assert(dmap['foo.example.com'] == 'wildcard') -- Any explicitly added entries will take precedence -- over the wildcard: dmap['explicit.example.com'] = 'explicit' assert(dmap['explicit.example.com'] == 'explicit') ``` -------------------------------- ### KumoMTA Base Policy Configuration Example Source: https://docs.kumomta.com/userguide/configuration/example?q= This Lua script serves as a complete base policy for a functional KumoMTA installation. It includes setup for sending IPs, DKIM signing, traffic shaping, webhook logging, and queue management, along with event handlers for spool and log configuration. Ensure all referenced TOML files and directories exist before loading. ```lua -- NOTE: This example policy is not meant to be used as-is, and will require some editing. -- We strongly recommend reading the User Guide chapter on configuration before working with -- this example policy. See https://docs.kumomta.com/userguide/configuration -- This file must be written to /opt/kumomta/etc/policy/init.lua for use. -- This require statement is needed in any script passed to KumoMTA. -- Includes from this policy script will not need this declared again. local kumo = require 'kumo' local utils = require 'policy-extras.policy_utils' -- Load the policy helpers to simplify common configuration use cases local shaping = require 'policy-extras.shaping' local queue_module = require 'policy-extras.queue' local listener_domains = require 'policy-extras.listener_domains' local sources = require 'policy-extras.sources' local dkim_sign = require 'policy-extras.dkim_sign' local log_hooks = require 'policy-extras.log_hooks' -- START SETUP -- Configure the sending IP addresses that will be used by KumoMTA to -- connect to remote systems using the sources.lua policy helper. -- Note that defining sources and pools does nothing without some form of -- policy in effect to assign messages to the source pools you have defined. -- WARNING: THIS WILL NOT LOAD WITHOUT THE source.toml FILE IN PLACE -- SEE https://docs.kumomta.com/userguide/configuration/sendingips/ sources:setup { '/opt/kumomta/etc/policy/sources.toml' } -- Configure DKIM signing. In this case we use the dkim_sign.lua policy helper. -- WARNING: THIS WILL NOT LOAD WITHOUT the dkim_data.toml FILE IN PLACE -- See https://docs.kumomta.com/userguide/configuration/dkim/ local dkim_signer = dkim_sign:setup { '/opt/kumomta/etc/policy/dkim_data.toml' } -- Load Traffic Shaping Automation Helper local shaper = shaping:setup_with_automation { publish = { 'http://127.0.0.1:8008' }, subscribe = { 'http://127.0.0.1:8008' }, extra_files = { '/opt/kumomta/etc/policy/shaping.toml' }, } -- Send a JSON webhook to a local network host. -- See https://docs.kumomta.com/userguide/operation/webhooks/ log_hooks:new_json { name = 'webhook', url = 'http://10.0.0.1:4242/log', log_parameters = { headers = { 'Subject', 'X-Customer-ID' }, }, } -- Configure queue management settings. These are not throttles, but instead -- control how messages flow through the queues. -- WARNING: ENSURE THAT WEBHOOKS AND SHAPING ARE SETUP BEFORE THE QUEUE HELPER FOR PROPER OPERATION -- WARNING: THIS WILL NOT LOAD WITHOUT the queues.toml FILE IN PLACE -- See https://docs.kumomta.com/userguide/configuration/queuemanagement/ local queue_helper = queue_module:setup { '/opt/kumomta/etc/policy/queues.toml' } -- END SETUP --START EVENT HANDLERS -- Called On Startup, handles initial configuration kumo.on('init', function() -- Define the default "data" spool location; this is where -- message bodies will be stored. -- See https://docs.kumomta.com/userguide/configuration/spool/ kumo.define_spool { name = 'data', path = '/var/spool/kumomta/data', kind = 'RocksDB', } -- Define the default "meta" spool location; this is where -- message envelope and metadata will be stored. kumo.define_spool { name = 'meta', path = '/var/spool/kumomta/meta', kind = 'RocksDB', } -- Configure publishing of TSA logs to automation daemon shaper.setup_publish() -- Configure logging to local disk. Separating spool and logs to separate -- disks helps reduce IO load and can help performance. -- See https://docs.kumomta.com/userguide/configuration/logging/ kumo.configure_local_logs { log_dir = '/var/log/kumomta', max_segment_duration = '1 minute', -- headers = { 'Subject', 'X-Customer-ID' }, } -- Configure bounce classification. -- See https://docs.kumomta.com/userguide/configuration/bounce/ kumo.configure_bounce_classifier { files = { '/opt/kumomta/share/bounce_classifier/iana.toml', }, } end) ``` -------------------------------- ### Example Usage Source: https://docs.kumomta.com/reference/kumo.mimepart/builder A complete example demonstrating how to use the builder to construct an email with plain text, HTML, and attachments. ```APIDOC ## Example Usage ### Description This example shows how to build an email with plain text, HTML content, and two attachments using the `kumo.mimepart.builder()`. ### Method (Demonstrates chained calls on the builder object) ### Endpoint N/A ### Request Example ```lua -- Build up an email with a couple of attachments/parts local builder = kumo.mimepart.builder() builder:text_plain 'Hello, plain' builder:text_html 'Hello, html' builder:attach( 'text/plain', 'I am a plain text file with no options specified' ) builder:attach('application/octet-stream', '\xaa\xbb', { file_name = 'binary.dat', }) local root = builder:build() print(root) ``` ### Response Example (The output will vary based on boundary strings and date) ``` Content-Type: multipart/mixed; boundary="mm-boundary" Mime-Version: 1.0 Date: Tue, 1 Jul 2003 10:52:37 +0200 --mm-boundary Content-Type: multipart/alternative; boundary="ma-boundary" --ma-boundary Content-Type: text/plain; charset="us-ascii" Hello, plain --ma-boundary Content-Type: text/html; charset="us-ascii" Hello, html --ma-boundary-- --mm-boundary Content-Type: text/plain Content-Transfer-Encoding: base64 SSBhbSBhIHBsYWluIHRleHQgZmlsZSB3aXRoIG5vIG9wdGlvbnMgc3BlY2lmaWVk --mm-boundary Content-Type: application/octet-stream Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="binary.dat" qrs= --mm-boundary-- ``` ``` -------------------------------- ### Rust Redis Cmd Usage Example Source: https://docs.kumomta.com/rustapi/mod_redis/fn.cmd.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Example of using the `cmd` function to create a PING command in Rust for Redis. This is the recommended way to start a command pipe. ```rust redis::cmd("PING"); ``` -------------------------------- ### Vector Capacity Example Source: https://docs.kumomta.com/rustapi/mailparsing/rfc5322_parser/struct.AddressList.html Demonstrates how to get the total capacity of a vector, which is the number of elements it can hold without reallocating. This example shows a basic usage and a special case for zero-sized elements. ```rust let mut vec: Vec = Vec::with_capacity(10); vec.push(42); assert!(vec.capacity() >= 10); ``` ```rust #[derive(Clone)] struct ZeroSized; fn main() { assert_eq!(std::mem::size_of::(), 0); let v = vec![ZeroSized; 0]; assert_eq!(v.capacity(), usize::MAX); } ``` -------------------------------- ### Start KumoProxy Server Source: https://docs.kumomta.com/userguide/operation/kumo-proxy Execute the KumoProxy binary to start the SOCKS5 proxy server. Replace with your desired listening address and port. ```bash /opt/kumomta/sbin/proxy-server --listen ``` -------------------------------- ### Get KumoMTA Version Source: https://docs.kumomta.com/userguide/operation/status Run this command to display the installed version of KumoMTA. This is important for support inquiries. ```bash $ /opt/kumomta/sbin/kumod --version ``` -------------------------------- ### Batched Webhook Example with Kumo Source: https://docs.kumomta.com/reference/kumo.jsonl/new_tailer This example shows how to use `new_tailer` to read log records and post them in batches to an HTTP endpoint. It includes retry logic for transient HTTP errors. ```lua local kumo = require 'kumo' kumo.on('main', function() local client = kumo.http.build_client {} local max_retries = 5 local retry_delay_seconds = 2 -- Perform the HTTP POST and return the response. local function post_batch(payload) return client :post('http://10.0.0.1:4242/log') :header('Content-Type', 'application/json') :body(payload) :send() end -- Encode the records as a JSON array, then post with retries. -- Returns only if the post succeeded; raises an error otherwise, -- leaving the batch uncommitted so the next run will retry it. local function process_batch(records) local payload = kumo.serde.json_encode(records) for attempt = 1, max_retries do local response = post_batch(payload) if response:status_is_success() then return end local status = response:status_code() local disposition = string.format( '%d %s: %s', status, response:status_reason(), response:text() ) -- 429 Too Many Requests and 5xx server errors are -- transient and worth retrying. 4xx client errors -- (other than 429) indicate a permanent problem with -- the request itself and are not worth retrying. local retryable = status == 429 or status >= 500 if not retryable or attempt == max_retries then -- We did not commit, so the next run will retry this batch. -- Sleep briefly before failing out so that a supervising -- process does not restart us too quickly. kumo.log_error( string.format( 'webhook post failed (attempt %d/%d), giving up: %s', attempt, max_retries, disposition ) ) kumo.time.sleep(5) error('webhook post failed: ' .. disposition) end -- Transient failure: wait before retrying. kumo.log_error( string.format( 'webhook post failed (attempt %d/%d), retrying in %ds: %s', attempt, max_retries, retry_delay_seconds, disposition ) ) kumo.time.sleep(retry_delay_seconds) end end local tailer = kumo.jsonl.new_tailer { directory = '/var/log/kumomta', max_batch_size = 100, max_batch_latency = '1s', checkpoint_name = 'webhook-poster', }, -- Only forward records for the 'customer-a' egress pool. function(record) return record.egress_pool == 'customer-a' end ) for batch in tailer:batches() do process_batch(batch:records()) batch:commit() end tailer:close() client:close() end) ``` -------------------------------- ### Get URL Origin (Other Scheme) Source: https://docs.kumomta.com/rustapi/kumo_api_client/struct.Url.html Checks if a URL with a non-standard scheme has a tuple origin. This example shows it does not. ```rust use url::{Host, Origin, Url}; let url = Url::parse("foo:bar")?; assert!(!url.origin().is_tuple()); ``` -------------------------------- ### Example: Writing records to a LogWriter Source: https://docs.kumomta.com/reference/kumo.jsonl/new_writer Demonstrates creating a LogWriter with specific configurations and writing records. Ensure the writer is closed after use. ```lua local kumo = require 'kumo' local writer = kumo.jsonl.new_writer { log_dir = '/var/log/kumomta/json', max_file_size = 268435456, -- 256 MiB max_segment_duration = '1h', compression_level = 3, suffix = '.zst', } writer:write_record { event = 'Delivery', id = 'abc123' } writer:write_record { event = 'Bounce', id = 'def456' } writer:close() ``` -------------------------------- ### Kumo Server Startup Configuration and Execution Source: https://docs.kumomta.com/rustapi/src/kumo_server_common/start.rs.html?search= Defines the `StartConfig` struct and its `run` method, which handles server initialization, logging setup, policy loading, and lifecycle management. It spawns tasks for machine info collection and manages the main initialization and shutdown futures. ```rust use crate::diagnostic_logging::LoggingConfig; use crate::nodeid::NodeId; use anyhow::Context; use chrono::{DateTime, Utc}; use config::RegisterFunc; use kumo_machine_info::MachineInfo; use kumo_server_lifecycle::LifeCycle; use kumo_server_runtime::rt_spawn; use parking_lot::Mutex; use std::future::Future; use std::path::Path; use std::sync::LazyLock; pub static ONLINE_SINCE: LazyLock> = LazyLock::new(Utc::now); pub static MACHINE_INFO: LazyLock>> = LazyLock::new(|| Mutex::new(None)); pub struct StartConfig<'a> { pub logging: LoggingConfig<'a>, pub lua_funcs: &'a [RegisterFunc], pub policy: &'a Path, } impl StartConfig<'_> { pub async fn run( self, init_future: INIT, shutdown_future: FINI, ) -> anyhow::Result<()> where INIT: Future> + Send + 'static, FINI: Future + Send + 'static, { LazyLock::force(&ONLINE_SINCE); self.logging.init()?; start_cpu_usage_monitor(); rustls::crypto::aws_lc_rs::default_provider() .install_default() .map_err(|_| anyhow::anyhow!("failed to install default crypto provider"))?; kumo_server_memory::setup_memory_limit().context("setup_memory_limit")?; prometheus::register(Box::new( tokio_metrics_collector::default_runtime_collector(), )) .context("failed to configure tokio-metrics-collector")?; for &func in self.lua_funcs { config::register(func); } config::set_policy_path(self.policy.to_path_buf()) .await .with_context(|| format!("Error evaluating policy file {:?}", self.policy))?; tokio::spawn(async move { let mut info = MachineInfo::new(); info.node_id.replace(NodeId::get().uuid.to_string()); info.query_cloud_provider().await; *MACHINE_INFO.lock() = Some(info); }); let mut life_cycle = LifeCycle::new(); let init_handle = rt_spawn("initialize", async move { let mut error = None; if let Err(err) = init_future.await { let err = format!("{err:#}"); tracing::error!("problem initializing: {err}"); LifeCycle::request_shutdown(Ok(())).await; error.replace(err); } // This log line is depended upon by the integration // test harness. Do not change or remove it without // making appropriate adjustments over there! tracing::info!("initialization complete"); error })?; let final_result = life_cycle.wait_for_shutdown().await; // after waiting for those to idle out, shut down logging shutdown_future.await; tracing::info!("Shutdown completed OK!"); if let Some(error) = init_handle.await? { anyhow::bail!("Initialization raised an error: {error}"); } if let Some(Err(error)) = final_result { anyhow::bail!("Shutdown due to error: {error}"); } Ok(()) } } ``` -------------------------------- ### Get Registered Functions Source: https://docs.kumomta.com/rustapi/src/config/lib.rs.html?search=std%3A%3Avec Retrieves a vector of registered functions. These functions are typically Lua callbacks or setup routines. ```rust fn get_funcs() -> Vec { FUNCS.lock().clone() } ``` -------------------------------- ### Script Creation and Execution Example Source: https://docs.kumomta.com/rustapi/mod_redis/struct.Script.html Demonstrates how to create a new Script object, add arguments, and invoke it on a Redis connection. ```APIDOC ## Script Represents a lua script that can be executed on the redis server. The object itself takes care of automatic uploading and execution. The script object itself can be shared and is immutable. ### `Script::new(code: &str) -> Script` Creates a new script object. ### `Script::arg(&self, arg: T) -> ScriptInvocation<'_>` Creates a script invocation object with an argument filled in. This method is generic over any type that implements `ToRedisArgs`. ### `Script::invoke(&self, con: &mut dyn ConnectionLike) -> Result` Invokes the script directly without arguments. This method is generic over any type that implements `FromRedisValue` and requires a mutable reference to a `ConnectionLike` object. It returns a `Result` which is either the deserialized script output or a `RedisError`. #### Example ```rust let script = redis::Script::new(r"\n return tonumber(ARGV[1]) + tonumber(ARGV[2]);\n"); let result = script.arg(1).arg(2).invoke(&mut con); assert_eq!(result, Ok(3)); ``` ``` -------------------------------- ### CidrMap Get Example Source: https://docs.kumomta.com/rustapi/src/cidr_map/map.rs.html?search= Demonstrates retrieving values from a CidrMap using IP addresses as keys. The `get` function parses the input string into an IP address and uses `get_prefix_match` to find the most specific matching CIDR entry. ```rust fn get<'a>(set: &'a CidrMap<&str>, key: &str) -> Option<&'a str> { let key = key.parse().unwrap(); set.get_prefix_match(key).copied() } ``` -------------------------------- ### Basic TimeQ Drain Example Source: https://docs.kumomta.com/rustapi/src/timeq/lib.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates creating a TimeQ, inserting items with different delays, draining the queue, and verifying its state. ```rust let item1 = Entry { id: 1, value: "foo", delay: Duration::from_millis(20), }; let item2 = Entry { id: 2, value: "bar", delay: Duration::from_millis(10), }; let item3 = Entry { id: 3, value: "baz", delay: Duration::from_millis(5), }; let mut queue = TimeQ::new(); queue.insert(&item1).unwrap(); queue.insert(&item2).unwrap(); queue.insert(&item3).unwrap(); let items = queue.drain(); assert_eq!(queue.len(), 0); assert!(queue.is_empty()); assert_eq!(items, vec![&item1, &item3, &item2]); ``` -------------------------------- ### S3 GET Request Signing and HTTP Client Integration Source: https://docs.kumomta.com/reference/kumo.crypto/aws_sign_v4 Example of signing an S3 GET request and then making the request using KumoMTA's HTTP client. Ensure the `Authorization` and `X-Amz-Date` headers are correctly set. ```lua local kumo = require 'kumo' local result = kumo.crypto.aws_sign_v4 { access_key = { key_data = 'AKIAIOSFODNN7EXAMPLE', }, secret_key = { key_data = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY', }, region = 'us-east-1', service = 's3', method = 'GET', uri = '/my-bucket/my-object.txt', query_params = {}, headers = { host = 'my-bucket.s3.amazonaws.com', }, payload = '', } http.request { url = 'https://my-bucket.s3.amazonaws.com/my-object.txt', method = 'GET', headers = { ['Authorization'] = result.authorization, ['X-Amz-Date'] = result.timestamp, ['Host'] = 'my-bucket.s3.amazonaws.com', }, } ``` -------------------------------- ### Iterating Over a Slice Source: https://docs.kumomta.com/rustapi/mailparsing/rfc5322_parser/struct.AddressList.html Use `iter()` to get an immutable iterator over the elements of a slice. The iterator yields elements from start to end. ```rust let x = &[1, 2, 4]; let mut iterator = x.iter(); assert_eq!(iterator.next(), Some(&1)); assert_eq!(iterator.next(), Some(&2)); assert_eq!(iterator.next(), Some(&4)); assert_eq!(iterator.next(), None); ``` -------------------------------- ### Example Searches Source: https://docs.kumomta.com/rustapi/config/epoch/struct.ConfigEpoch.html?search= Demonstrates common search patterns for types and conversions. ```rust * std::vec ``` ```rust * u32 -> bool ``` ```rust * Option, (T -> U) -> Option ``` -------------------------------- ### Parse RFC 5965 ARF Report (Example 3 - Partial) Source: https://docs.kumomta.com/rustapi/src/kumo_log_types/rfc5965.rs.html?search= Initiates parsing of a third ARF report, showing the start of the structure including feedback type, user agent, and version. The full content of this example is truncated in the source. ```rust #[test] fn rfc5965_3() { let result = ARFReport::parse(include_bytes!("../data/rfc5965/3.eml")).unwrap(); k9::snapshot!( result, r#"" Some( ARFReport { feedback_type: "abuse", user_agent: "Yahoo!-Mail-Feedback/2.0", version: "0.1", arrival_date: Some( ``` -------------------------------- ### StartConfig::run Source: https://docs.kumomta.com/rustapi/kumo_server_common/start/struct.StartConfig.html?search=u32+-%3E+bool Asynchronously runs the server with provided initialization and shutdown futures. This is the main entry point for starting the server process managed by StartConfig. ```APIDOC ## StartConfig::run ### Description Asynchronously runs the server with provided initialization and shutdown futures. This is the main entry point for starting the server process managed by StartConfig. ### Signature `pub async fn run(self, init_future: INIT, shutdown_future: FINI) -> Result<()>` ### Type Parameters * `INIT`: A future that resolves to a `Result<()>` and is `Send + 'static`. This future is executed for initialization. * `FINI`: A future that resolves to `()` and is `Send + 'static`. This future is executed for shutdown. ### Parameters * `self`: The `StartConfig` instance. * `init_future`: The future to execute for initialization. * `shutdown_future`: The future to execute for shutdown. ### Returns * `Result<()>`: Returns `Ok(())` on successful execution, or an error if initialization fails. ``` -------------------------------- ### Rust Regex: Capture groups starting from a specific position Source: https://docs.kumomta.com/rustapi/kumo_api_types/shaping/struct.Regex.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Use `captures_from_pos` to find capture groups for the first match in a string, starting the search from a specified byte index. This example captures a number at the beginning of a line after a certain position. ```rust let re = Regex::new(r"(?m:^)(\d+)").unwrap(); let text = "1 test 123\n2 foo"; let captures = re.captures_from_pos(text, 7).unwrap().unwrap(); let group = captures.get(1).unwrap(); assert_eq!(group.as_str(), "2"); assert_eq!(group.start(), 11); assert_eq!(group.end(), 12); ``` -------------------------------- ### MPSC Queue Example Source: https://docs.kumomta.com/reference/kumo.mpsc/define?q= An example demonstrating the initialization, spawning of a consumer task, and submission of items to an MPSC queue. The consumer task receives items in batches. ```lua local function get_queue() return kumo.mpsc.define 'my-example-queue' end kumo.on('init', function() -- Spawn a task that will process items that were sent to the queue. -- It will try to pull items in batches of up to 128 at a time kumo.spawn_task { event_name = 'my.queue.task', args = {}, } end) kumo.on('my.queue.task', function(args) -- Get a reference to the unbounded queue we created during `init` local q = get_queue() while true do local batch = q:recv_many(128) print(string.format('got a batch of %d items', #batch)) for idx, item in ipairs(batch) do print(string.format('item idx %d: %s', idx, item)) end end end) -- Calling this function will submit an item to the queue local function submit_item(item) local q = get_queue() q:send(item) end ``` -------------------------------- ### Basic tsa_init Event Handler Source: https://docs.kumomta.com/reference/events/tsa_init?q= A minimal example of an event handler for tsa_init. This is often used as a starting point for more complex configurations. ```lua kumo.on('tsa_init', function() end) ``` -------------------------------- ### Kumod Server Command Syntax Source: https://docs.kumomta.com/userguide/general/about Example of the kumod server command syntax, showing optional parameters like --user. ```bash **`kumod`**_`--policy simple-policy.lua [--user] someuser`_ ``` -------------------------------- ### Example systemd Service Configuration with Vault Variables Source: https://docs.kumomta.com/userguide/policy/hashicorp_vault?q= An example of a complete systemd service file for KumoMTA, including environment variables for Vault access. ```bash [Unit] Description=KumoMTA SMTP service After=syslog.target network.target Conflicts=sendmail.service exim.service postfix.service [Service] Type=simple Restart=always ExecStart=/opt/kumomta/sbin/kumod --policy /opt/kumomta/etc/policy/init.lua --user kumod # Allow sufficient time to wrap up in-flight tasks and safely # write out pending data TimeoutStopSec=300 Environment=VAULT_ADDR='http://127.0.0.1:8200' Environment=VAULT_TOKEN='SAMPLE-TOKEN' [Install] WantedBy=multi-user.target ``` -------------------------------- ### Get Mailbox Portion of Address Source: https://docs.kumomta.com/reference/address/user?q= Use this to retrieve the local part of an email address. For example, for 'first.last@example.com', it returns 'first.last'. ```lua local user = address.user ``` -------------------------------- ### Get Mailbox Portion of Address Source: https://docs.kumomta.com/reference/address/user Use this to extract the local part (mailbox) from an email address. For example, 'first.last' from 'first.last@example.com'. ```lua local user = address.user ``` -------------------------------- ### Configuring proxy.start_proxy_listener with TLS and Authentication Source: https://docs.kumomta.com/reference/proxy/start_proxy_listener Enables TLS encryption and requires authentication for the SOCKS5 proxy server. Ensure that the certificate and private key paths are correctly specified. ```lua kumo.on('proxy_init', function() proxy.start_proxy_listener { listen = '0.0.0.0:1080', use_tls = true, tls_certificate = '/path/to/cert.pem', tls_private_key = '/path/to/key.pem', require_auth = true, } end) kumo.on('proxy_server_auth_rfc1929', function(username, password, conn_meta) -- Validate credentials here return username == 'user' and password == 'secret' end) ``` -------------------------------- ### Extract Domain from Address Source: https://docs.kumomta.com/reference/address/domain Use this function to get the domain part of an email address. For example, 'first.last@example.com' will return 'example.com'. ```lua local domain = address.domain ``` -------------------------------- ### New JSONL Tailer Example Source: https://docs.kumomta.com/reference/kumo.jsonl/new_tailer This example demonstrates how to create a new JSONL tailer, iterate through batches and records, filter records by type, and commit batches. ```lua local kumo = require 'kumo' local tailer = kumo.jsonl.new_tailer { directory = '/var/log/kumomta', pattern = '*.zst', max_batch_size = 500, max_batch_latency = '250ms', checkpoint_name = 'delivery-processor', } for batch in tailer:batches() do for record in batch:iter_records() do if record.type == 'Delivery' then print('delivered: ' .. record.id) end end batch:commit() end tailer:close() ``` -------------------------------- ### Create and Use a Multi-Tailer for JSONL Files Source: https://docs.kumomta.com/reference/kumo.jsonl/new_multi_tailer Demonstrates setting up a multi-tailer to monitor a directory for compressed JSONL files. It defines two consumers, 'deliveries' and 'bounces', each with specific filtering logic and batching configurations. The code then iterates through batches of records, processes them, commits them, and finally closes the tailer. ```lua local kumo = require 'kumo' local tailer = kumo.jsonl.new_multi_tailer { directory = '/var/log/kumomta', pattern = '*.zst', consumers = { { name = 'deliveries', checkpoint_name = 'cp-del', max_batch_size = 200, max_batch_latency = '500ms', filter = function(record) return record.type == 'Delivery' end, }, { name = 'bounces', checkpoint_name = 'cp-bounce', max_batch_latency = '5s', filter = function(record) return record.type == 'Bounce' or record.type == 'TransientFailure' end, }, }, } for batches in tailer:batches() do for _, batch in ipairs(batches) do local name = batch:consumer_name() for record in batch:iter_records() do print(name .. ': ' .. record.id) end batch:commit() end end tailer:close() ``` -------------------------------- ### Vault KeySource Get Operation Source: https://docs.kumomta.com/rustapi/src/data_loader/lib.rs.html?search=std%3A%3Avec Retrieves data from Vault using a KeySource. This example shows fetching data previously stored with `put`. ```rust let source = vault.make_source("foo"); let data = source.get().await?; assert_eq!(data, b"bar"); ``` -------------------------------- ### proxy.start_proxy_listener Source: https://docs.kumomta.com/reference/proxy/start_proxy_listener?q= Configures and starts a SOCKS5 proxy server. This function is available only to the `proxy-server` executable and should be called from within your `proxy_init` event handler. ```APIDOC ## proxy.start_proxy_listener ### Description Configures and starts a SOCKS5 proxy server that implements the SOCKS5 protocol. This allows KumoMTA's egress sources to route outbound connections through the proxy, which is useful for controlling egress IP addresses or routing traffic through specific network paths. ### Method This is a Lua function call within the KumoMTA event handler. ### Parameters `PARAMS` is a lua table that can accept the following keys: #### Proxy Listener Parameters * **hostname** (string) - Optional - The hostname to bind the proxy listener to. If not specified, it defaults to the value of the `listen` parameter. * **listen** (string) - Required - The address and port to listen on (e.g., '0.0.0.0:1080'). * **require_auth** (boolean) - Optional - If true, requires authentication for proxy connections. * **tcp_keepalive** (boolean) - Optional - Enables TCP keepalive probes. * **timeout** (duration) - Optional - The maximum time a connection can remain idle before being closed. * **tls_certificate** (string) - Optional - Path to the TLS certificate file. Required if `use_tls` is true. * **tls_private_key** (string) - Optional - Path to the TLS private key file. Required if `use_tls` is true. * **use_splice** (boolean) - Optional - Enables the use of splice for efficient data transfer. * **use_tls** (boolean) - Optional - If true, enables TLS encryption for the proxy listener. ### Request Example ```lua kumo.on('proxy_init', function() proxy.start_proxy_listener { listen = '0.0.0.0:1080', use_tls = true, tls_certificate = '/path/to/cert.pem', tls_private_key = '/path/to/key.pem', require_auth = true, } end) ``` ### Response This function does not return a value directly. Its effect is to start the proxy listener. ### Authentication Callback (if `require_auth` is true) #### `proxy_server_auth_rfc1929(username, password, conn_meta)` This function is called to authenticate incoming proxy connections when `require_auth` is set to true. * **username** (string) - The username provided by the client. * **password** (string) - The password provided by the client. * **conn_meta** (table) - Metadata about the connection. **Returns**: `boolean` - Returns `true` if authentication is successful, `false` otherwise. ### Authentication Callback Example ```lua kumo.on('proxy_init', function() proxy.start_proxy_listener { listen = '0.0.0.0:1080', require_auth = true, } end) kumo.on('proxy_server_auth_rfc1929', function(username, password, conn_meta) -- Validate credentials here return username == 'user' and password == 'secret' end) ``` ``` -------------------------------- ### DNS Records for bar.com Source: https://docs.kumomta.com/userguide/configuration/rollup Example DNS MX and A records for a hypothetical domain bar.com, demonstrating a similar mail routing setup as foo.com. ```bash $ dig +short mx bar.com 1 bar-com.mail.protection.outlook.com. ``` ```bash $ dig +short a bar.com.mail.protection.outlook.com. 104.47.24.36 104.47.25.36 ``` -------------------------------- ### Get Memory Status Source: https://docs.kumomta.com/rustapi/kumo_server_memory/fn.memory_status.html?search=u32+-%3E+bool Call this function to retrieve the overall memory status of the server. No specific setup or imports are required beyond the crate itself. ```rust pub fn memory_status() -> MemoryStatus ``` -------------------------------- ### Basic Cmd Creation Source: https://docs.kumomta.com/rustapi/mod_redis/struct.Cmd.html?search= Demonstrates the basic usage of creating a Redis command using Cmd::new() and chaining arguments. ```rust redis::Cmd::new().arg("SET").arg("my_key").arg(42); ``` -------------------------------- ### Get ACL Cache TTL Source: https://docs.kumomta.com/rustapi/kumo_server_common/authn_authz/fn.get_acl_cache_ttl.html Retrieves the time-to-live duration for the Access Control List (ACL) cache. No setup or imports are required for this function. ```rust pub fn get_acl_cache_ttl() -> Duration ``` -------------------------------- ### Connection Rate Examples Source: https://docs.kumomta.com/reference/kumo/make_egress_path/max_connection_rate Examples of how to specify connection rate limits using different time periods and formats. ```text "10/s" -- 10 per second ``` ```text "10/sec" -- 10 per second ``` ```text "10/second" -- 10 per second ``` ```text "50/m" -- 50 per minute ``` ```text "50/min" -- 50 per minute ``` ```text "50/minute" -- 50 per minute ``` ```text "1,000/hr" -- 1000 per hour ``` ```text "1_000/h" -- 1000 per hour ``` ```text "1000/hour" -- 1000 per hour ``` ```text "10_000/d" -- 10,000 per day ``` ```text "10,000/day" -- 10,000 per day ``` -------------------------------- ### Basic proxy.start_proxy_listener Configuration Source: https://docs.kumomta.com/reference/proxy/start_proxy_listener Starts a SOCKS5 proxy listener on the specified address and port. This is the most basic configuration for the proxy server. ```lua kumo.on('proxy_init', function() proxy.start_proxy_listener { listen = '0.0.0.0:1080', } end) ``` -------------------------------- ### Get MX Timeout Duration Source: https://docs.kumomta.com/rustapi/dns_resolver/fn.get_mx_timeout.html Retrieves the configured timeout duration for MX record lookups. No setup or imports are required to use this function. ```rust pub fn get_mx_timeout() -> Duration ``` -------------------------------- ### Trim Start Matches Example Source: https://docs.kumomta.com/rustapi/kumo_prometheus/parser/struct.InternString.html?search= Illustrates `trim_start_matches` which repeatedly removes all matching prefixes from a string slice. The pattern can be a character, string slice, or a closure. ```rust let x: &[_] = &['1', '2']; assert_eq!("12foo1bar12".trim_start_matches(x), "foo1bar12"); ``` -------------------------------- ### Example Searches Source: https://docs.kumomta.com/rustapi/cidr_map/fn.register.html?search= These are example search queries that can be used within the system. They demonstrate different patterns for searching, including standard library types, type conversions, and generic type transformations. ```text std::vec ``` ```text u32 -> bool ``` ```text Option, (T -> U) -> Option ``` -------------------------------- ### Setting 'resent_cc' Header Source: https://docs.kumomta.com/rustapi/src/mod_mimepart/headers.rs.html?search=std%3A%3Avec Example of using the 'accessor' macro to define Lua methods for getting and setting the 'resent_cc' header, expecting an AddressList type. ```rust accessor!( "resent_cc", resent_cc, "set_resent_cc", ```