### Configure MIMEDefang Build Options Source: https://github.com/the-mcgrail-foundation/mimedefang/blob/master/README.md Use these options during the ./configure step to customize installation paths and features. For example, specify the Sendmail binary location or the spool directory. ```bash ./configure make make install ``` ```bash ./configure --sysconfdir=/usr/local/etc ``` ```bash ./configure --sysconfdir=/usr/local/etc --with-confsubdir=mimedefang ``` ```bash ./configure --sysconfdir=/usr/local/etc --with-confsubdir= ``` ```bash ./configure --with-spooldir=DIRNAME ``` ```bash ./configure --with-quarantinedir=DIR2 ``` -------------------------------- ### Configure MIMEDefang Startup Script Source: https://github.com/the-mcgrail-foundation/mimedefang/blob/master/README.md Ensure MIMEDefang starts with Sendmail by adding these lines to your system's startup scripts. Remember to remove the socket file before starting and kill MIMEDefang processes during shutdown. ```bash rm -f /var/spool/MIMEDefang/mimedefang.sock /usr/local/bin/mimedefang -p /var/spool/MIMEDefang/mimedefang.sock & ``` -------------------------------- ### MIMEDefang filter_begin Hook for Initial Message Processing Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt The filter_begin hook is called once at the start of each message, before any MIME parts are processed. Use it for whole-message actions like virus scanning or suspicious header detection. Ensure necessary modules are imported and actions are called appropriately. ```perl # /etc/mail/mimedefang-filter use Mail::MIMEDefang::Antivirus; our $FoundVirus = 0; sub filter_begin { my ($entity) = @_; # Drop messages with suspicious characters in headers immediately if ($SuspiciousCharsInHeaders) { action_quarantine_entire_message("Suspicious characters in headers"); return action_discard(); } # Copy original message to work dir so virus scanners can read it md_copy_orig_msg_to_work_dir_as_mbox_file(); # Scan with every installed virus scanner my ($code, $category, $action) = message_contains_virus(); $FoundVirus = ($category eq "virus"); if ($FoundVirus) { md_syslog('warning', "Virus detected: $VirusName — discarding"); return action_discard(); } if ($action eq "tempfail") { action_tempfail("Problem running virus scanner"); } } ``` -------------------------------- ### Scan Entire Message for Viruses Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Scans the whole message using all installed antivirus scanners. Returns a code, category ('virus', 'suspicious', 'ok'), and action. Use this for a comprehensive virus check on the entire message content. ```perl use Mail::MIMEDefang::Antivirus; sub filter_begin { my ($entity) = @__; md_copy_orig_msg_to_work_dir_as_mbox_file(); my ($code, $category, $action) = message_contains_virus(); if ($category eq "virus") { md_syslog('warning', "Virus: $VirusName from $RelayAddr"); md_graphdefang_log('virus', $VirusName, $RelayAddr); return action_discard(); } if ($action eq "tempfail") { return action_tempfail("Virus scanner error"); } } ``` -------------------------------- ### MIMEDefang filter Hook for Leaf MIME Part Processing Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt The filter hook is invoked once per leaf MIME part. It's the primary decision point for individual parts. Always return after calling exactly one action function. This example demonstrates rejecting 'message/partial' and dropping dangerous attachments. ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; return if message_rejected(); # skip work if already bounced/discarded # Reject message/partial — reassembly attack vector if (lc($type) eq "message/partial") { return action_bounce("message/partial not accepted here"); } # Drop dangerous Windows executable attachments my $bad = '(exe|bat|cmd|com|pif|scr|vbs|js|jse|wsf|wsh|msi|dll|sys)'; if (re_match($entity, '\.' . $bad . '\.*$')) { return action_drop_with_warning( "Attachment '$fname' was removed because it may contain malware.\n" ); } # Scan individual MIME parts with ClamAV if available if ($Features{"Path:CLAMD"}) { my ($code, $category, $action) = entity_contains_virus_clamd($entity); if ($category eq "virus") { return action_quarantine($entity, "Part '$fname' contains virus: $VirusName"); } } return action_accept(); } ``` -------------------------------- ### message_contains_virus Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Scans the entire message using all installed antivirus scanners. ```APIDOC ## message_contains_virus ### Description Scans the entire message using all installed antivirus scanners. ### Method Perl Subroutine ### Parameters None. ### Response Returns a list containing: - `$code` (numeric): The result code from the scanner. - `$category` (string): 'virus', 'suspicious', or 'ok'. - `$action` (string): The suggested action ('discard', 'tempfail', etc.). ``` -------------------------------- ### Initialize and use database for greylisting Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Connects to a SQLite database to manage greylisting. The `filter_sender` function uses `action_greylist` to determine if a message should be temporarily failed or rejected based on sender, recipient, and IP address. ```perl use DBI; my $DBH; sub filter_initialize { $DBH = DBI->connect("dbi:SQLite:dbname=/var/lib/mimedefang/greylist.db", "", "", { RaiseError => 1 }); $DBH->do(q{CREATE TABLE IF NOT EXISTS greylist ( sender_host_ip TEXT, sender TEXT, recipient TEXT, first_received INTEGER, last_received INTEGER, known_ip INTEGER )}); } sub filter_sender { my ($sender, $ip, $helo, $rcpt) = @_; my $result = action_greylist($DBH, $sender, $rcpt, $ip, 300, # min_retry: 5 minutes 14400); # max_retry: 4 hours if ($result eq "tempfail") { return action_tempfail("Greylisted — please retry in 5 minutes"); } if ($result eq "reject") { return action_bounce("Too much time has passed; resend the message"); } return "continue"; } sub filter_cleanup { $DBH->disconnect() if defined $DBH; } ``` -------------------------------- ### action_accept_with_warning Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Accepts the current MIME part but appends a warning message. This is useful for parts that are allowed but might require user attention. ```APIDOC ## action_accept_with_warning ### Description Accept part but append a warning. ### Parameters * `warning_text` (string) - The warning message to append. ### Usage in filter ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; if ($fname =~ \.doc$/i) { return action_accept_with_warning( "Warning: Microsoft Word files may contain macros.\n" ); } return action_accept(); } ``` ``` -------------------------------- ### Initialize and Check SpamAssassin with Spamc Client Protocol Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Uses the SpamAssassin 4.x client protocol (spamc) for scanning. Requires initialization with `md_spamc_init` and subsequent checks with `md_spamc_check`. Suitable for environments where the spamc protocol is preferred. ```perl use Mail::MIMEDefang::Antispam; my $SA_CLIENT; sub filter_initialize { $SA_CLIENT = md_spamc_init('localhost', 783, undef, 512*1024); } sub filter_end { my ($entity) = @__; return if message_rejected(); return unless defined $SA_CLIENT; my ($score, $threshold, $report, $is_spam) = md_spamc_check($SA_CLIENT); if (defined $score && $is_spam) { action_change_header("X-Spam-Score", "$score"); md_graphdefang_log('spam', $score, $RelayAddr); } } ``` -------------------------------- ### Accept part and append warning with action_accept_with_warning Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use action_accept_with_warning() to keep a MIME part but append a plain-text warning message. This is useful for alerting users about potentially risky content without removing it. ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; if ($fname =~ /\.doc$/i) { return action_accept_with_warning( "Warning: Microsoft Word files may contain macros.\n" ); } return action_accept(); } ``` -------------------------------- ### action_quarantine Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Drops the part, saves it to a quarantine directory, and notifies the administrator. ```APIDOC ## action_quarantine ### Description Quarantines a specific part of an email message. This action saves the affected part to a designated quarantine directory and typically involves notifying an administrator about the event. ### Method Not applicable (function call within a script) ### Endpoint Not applicable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```perl action_quarantine($entity, "Attachment '$fname' quarantined — virus: $VirusName\n"); ``` ### Response #### Success Response (200) Not applicable (function return value indicates action) #### Response Example Not applicable ``` -------------------------------- ### md_spamc_init / md_spamc_check Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Initializes and uses the SpamAssassin 4.x client protocol for scanning messages. ```APIDOC ## md_spamc_init / md_spamc_check ### Description Initializes and uses the SpamAssassin 4.x client protocol for scanning messages. ### Method Perl Subroutines ### Parameters for md_spamc_init - `host` (string): The hostname or IP address of the SpamAssassin daemon. - `port` (numeric): The port the SpamAssassin daemon is listening on. - `timeout` (numeric): Connection timeout in seconds. - `max_size` (numeric): Maximum message size in bytes. ### Parameters for md_spamc_check - `$SA_CLIENT` (object): The client object returned by `md_spamc_init`. ### Response from md_spamc_check Returns a list containing: - `$score` (numeric): The spam score. - `$threshold` (numeric): The spam threshold. - `$report` (string): The SpamAssassin report. - `$is_spam` (boolean): True if the message is considered spam. ``` -------------------------------- ### action_replace_with_url Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Replaces an attachment with a downloadable URL. ```APIDOC ## action_replace_with_url ### Description Replaces a large or potentially risky attachment with a URL that allows the recipient to download it. This is useful for managing large files or for security reasons. ### Method Not applicable (function call within a script) ### Endpoint Not applicable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```perl action_replace_with_url($entity, "/var/www/attachments", "https://mail.example.com/attachments", "Large attachment available at: _URL_\n", $fname); ``` ### Response #### Success Response (200) Not applicable (function return value indicates action) #### Response Example Not applicable ``` -------------------------------- ### Append HTML boilerplate before Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Appends an HTML footer to HTML parts before the closing `` tag. The last argument `0` ensures it only affects the first matching part. ```perl sub filter_end { my ($entity) = @_; return if message_rejected(); my $html_footer = '

Confidential communication.

'; append_html_boilerplate($entity, $html_footer, 0); } ``` -------------------------------- ### Accept current MIME part unchanged with action_accept Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use action_accept() to keep the current MIME part as is. This is often used as a default action or after specific conditions are met. ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; # Accept text parts unconditionally return action_accept() if $type =~ m{^text/}; # ...other logic... return action_accept(); } ``` -------------------------------- ### Delete part and add warning with action_drop_with_warning Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use action_drop_with_warning() to remove a MIME part and insert a plain-text warning message in its place. This informs the recipient about the removed content. ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; if ($fname =~ /\.exe$/i) { return action_drop_with_warning( "The attachment '$fname' was removed because .exe files are not allowed.\n" ); } return action_accept(); } ``` -------------------------------- ### Detect Bogus MX Hosts Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use `md_get_bogus_mx_hosts()` to detect domains with private or bogus MX records. Extract the sender domain, check for bogus MX records, log a warning, and bounce mail if found. ```perl sub filter_begin { my ($entity) = @_; # Extract sender domain (my $domain = $Sender) =~ s/.*@//; $domain =~ s/>$//; my @bogus = md_get_bogus_mx_hosts($domain); if (@bogus) { md_syslog('warning', "Domain $domain has bogus MX: @bogus"); return action_bounce("Sender domain has invalid MX records"); } } ``` -------------------------------- ### Match filename/extension across MIME fields Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Uses `re_match` and `re_match_ext` to check filenames and extensions against regular expressions. `re_match_in_zip_directory` can be used to scan within ZIP archives. ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; # re_match checks Content-Disposition.filename, Content-Type.name, and # Content-Description against the regex if (re_match($entity, '\.(exe|bat|scr|pif)\.*$')) { return action_drop_with_warning("Dangerous attachment removed.\n"); } # re_match_ext checks only the extension portion if (re_match_ext($entity, '\.(zip|rar|7z)$')) { md_syslog('info', "Archive attachment: $fname"); } # Check inside ZIP archives for dangerous files if (re_match($entity, '\.zip$') && $Features{"Archive::Zip"}) { my $path = $entity->bodyhandle->path; if (re_match_in_zip_directory($path, '\.(exe|bat)\.*$')) { return action_drop_with_warning("ZIP contains executable — removed.\n"); } } return action_accept(); } ``` -------------------------------- ### Find the first text/plain MIME part Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Locates the first MIME entity of type 'text/plain', optionally skipping PGP-signed containers. Logs the path to the body handle if found. ```perl use Mail::MIMEDefang::MIME; sub filter_end { my ($entity) = @_; # Find the first text/plain part (skipping PGP-signed containers) my $plain = find_part($entity, "text/plain", 1); if (defined $plain) { md_syslog('info', "text/plain body path: " . $plain->bodyhandle->path); } } ``` -------------------------------- ### Write to Syslog Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use `md_syslog()` to write messages to syslog from within the filter. It automatically prepends the queue ID when available. Use different log levels like 'info', 'warning', and 'err'. ```perl # Automatically prepends the queue ID ($MsgID) when available md_syslog('info', "Processing message from $Sender"); md_syslog('warning', "Suspicious attachment: $fname"); md_syslog('err', "Virus scanner failed with code $code"); ``` -------------------------------- ### action_accept Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Accepts the current MIME part unchanged. This is a fundamental action used within filter functions to indicate that a part should be processed normally. ```APIDOC ## action_accept ### Description Accept the current MIME part unchanged. ### Usage in filter ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; # Accept text parts unconditionally return action_accept() if $type =~ m{^text/}; # ...other logic... return action_accept(); } ``` ``` -------------------------------- ### Replace Attachment with Download URL - MIMEDefang Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use to replace a large or potentially dangerous attachment with a link to download it from a specified URL. Requires specifying document root, base URL, and a message template. ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; if ($type =~ m{^video/} || -s $entity->bodyhandle->path > 10*1024*1024) { return action_replace_with_url( $entity, "/var/www/attachments", # document root on disk "https://mail.example.com/attachments", # base URL "Large attachment available at: _URL_\n", # _URL_ is replaced $fname # optional Content-Disposition data ); } return action_accept(); } ``` -------------------------------- ### Replace part with warning using action_replace_with_warning Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use action_replace_with_warning() to substitute a MIME part with a plain-text warning message. This is suitable for replacing potentially harmful content like executables. ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; if ($type eq "application/x-msdownload") { return action_replace_with_warning( "An executable attachment was replaced by this notice.\n" . "Please contact the sender to obtain the file via another method.\n" ); } return action_accept(); } ``` -------------------------------- ### md_get_bogus_mx_hosts Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Detects domains with private or bogus MX records. ```APIDOC ## md_get_bogus_mx_hosts — detect domains with private/bogus MX records ### Description Checks a domain's Mail Exchanger (MX) records to detect if they point to private or otherwise invalid IP addresses. Returns a list of bogus MX hosts found. ### Method Perl function call ### Parameters - **domain** (string) - The domain name to check. ### Response - **bogus_mx_hosts** (array) - An array of strings, where each string is a bogus MX host found for the domain. Returns an empty array if no bogus MX records are detected. ### Request Example ```perl sub filter_begin { my ($entity) = @_; # Extract sender domain (my $domain = $Sender) =~ s/.*@//; $domain =~ s/>$//; my @bogus = md_get_bogus_mx_hosts($domain); if (@bogus) { md_syslog('warning', "Domain $domain has bogus MX: @bogus"); return action_bounce("Sender domain has invalid MX records"); } } ``` ### Response Example (Implicitly used within the `filter_begin` subroutine) ``` -------------------------------- ### Fetch DMARC Policy Record Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use `md_get_dmarc_record()` to fetch the DMARC policy TXT record for a given domain. Extract the sender domain, retrieve the DMARC record, add it to headers, and log it. ```perl sub filter_end { my ($entity) = @_; (my $domain = $Sender) =~ s/.*@//; $domain =~ s/>$//; my $dmarc = md_get_dmarc_record($domain); if (defined $dmarc) { action_add_header("X-DMARC-Policy", $dmarc); md_syslog('info', "DMARC for $domain: $dmarc"); } } ``` -------------------------------- ### Integrate MIMEDefang with Sendmail m4 Configuration Source: https://github.com/the-mcgrail-foundation/mimedefang/blob/master/README.md Add this line to your Sendmail m4 configuration file to enable MIMEDefang as an input mail filter. Adjust the socket path if your spool directory differs. ```m4 INPUT_MAIL_FILTER(`mimedefang', `S=unix:/var/spool/MIMEDefang/mimedefang.sock, F=T, T=S:360s;R:360s;E:15m') ``` -------------------------------- ### action_replace_with_warning Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Replaces the current MIME part with a plain-text warning message. This is used when a part needs to be removed but the recipient should be informed about the replacement. ```APIDOC ## action_replace_with_warning ### Description Replace part with a plain-text warning. ### Parameters * `warning_text` (string) - The warning message to use as replacement. ### Usage in filter ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; if ($type eq "application/x-msdownload") { return action_replace_with_warning( "An executable attachment was replaced by this notice.\n" . "Please contact the sender to obtain the file via another method.\n" ); } return action_accept(); } ``` ``` -------------------------------- ### action_add_part Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Inserts a new MIME part into the message, such as a disclaimer. ```APIDOC ## action_add_part ### Description Inserts a new MIME part into an existing email message. This can be used to append information like legal disclaimers or other content as a separate part of the email. ### Method Not applicable (function call within a script) ### Endpoint Not applicable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```perl action_add_part($entity, "text/plain", "-suggest", "CONFIDENTIAL: This message is intended only for its addressee.\n", "disclaimer.txt", "inline"); ``` ### Response #### Success Response (200) Not applicable (function return value indicates action) #### Response Example Not applicable ``` -------------------------------- ### action_quarantine_entire_message Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Quarantines the complete raw message when a virus is detected. ```APIDOC ## action_quarantine_entire_message ### Description Quarantines the entire raw email message. This is typically used when a threat is detected within the message itself, such as a virus. ### Method Not applicable (function call within a script) ### Endpoint Not applicable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```perl action_quarantine_entire_message("Virus found: $VirusName"); ``` ### Response #### Success Response (200) Not applicable (function return value indicates action) #### Response Example Not applicable ``` -------------------------------- ### Append text to plain-text MIME parts Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Appends a disclaimer string to the first 'text/plain' part of a MIME entity. Set the last argument to 1 to append to all 'text/plain' parts. ```perl sub filter_end { my ($entity) = @_; return if message_rejected(); my $disclaimer = <<'END'; --- This communication is intended solely for the named addressee. END # Append to only the first text/plain part (pass 1 to append to all) append_text_boilerplate($entity, $disclaimer, 0); } ``` -------------------------------- ### Sign Message with DKIM Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Signs the email message using DKIM and returns the DKIM-Signature header. Requires specifying the private key file, algorithm, canonicalization, domain, and selector. Use this to add DKIM signatures to outgoing mail. ```perl use Mail::MIMEDefang::DKIM; sub filter_end { my ($entity) = @__; return if message_rejected(); my ($hdr_name, $hdr_value) = md_dkim_sign( '/etc/mail/dkim/example.com.key', # private key file 'rsa-sha256', # algorithm 'relaxed/relaxed', # canonicalization 'example.com', # domain 'mail', # selector => mail._domainkey.example.com ); if (defined $hdr_name && defined $hdr_value) { action_insert_header($hdr_name, $hdr_value, 0); } else { md_syslog('err', "DKIM signing failed"); } } ``` -------------------------------- ### action_drop_with_warning Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Deletes the current MIME part and appends a warning text part. This informs the recipient that a part was removed and why. ```APIDOC ## action_drop_with_warning ### Description Delete part and add a warning text part. ### Parameters * `warning_text` (string) - The warning message to append. ### Usage in filter ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; if ($fname =~ \.exe$/i) { return action_drop_with_warning( "The attachment '$fname' was removed because .exe files are not allowed.\n" ); } return action_accept(); } ``` ``` -------------------------------- ### relay_is_blacklisted Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Performs a single DNS lookup against a Real-time Blackhole List (RBL) for a given IP address. ```APIDOC ## relay_is_blacklisted — single RBL DNS lookup ### Description Performs a single DNS lookup against a specified RBL for a given IP address. Returns a truthy value if the IP is listed, and a falsy value otherwise. ### Method Perl function call ### Parameters - **RelayAddr** (string) - The IP address to check. - **RBL_Domain** (string) - The domain name of the RBL to query (e.g., 'zen.spamhaus.org'). ### Response - **result** (string or undef) - If the IP is listed, returns a string containing DNS lookup details; otherwise, returns `undef`. ### Request Example ```perl use Mail::Mail::MIMEDefang::Net; sub filter_begin { my ($entity) = @_; my $result = relay_is_blacklisted($RelayAddr, 'zen.spamhaus.org'); if ($result) { md_syslog('warning', "Relay $RelayAddr listed in Spamhaus ZEN: $result"); return action_bounce("Your IP is blacklisted ($result)", 554, "5.7.1"); } } ``` ### Response Example (Implicitly used within the `filter_begin` subroutine) ``` -------------------------------- ### Routable IP Address Checks Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use `is_public_ip4_address()` and `is_public_ip6_address()` to check if an IP address is routable. Log a message and skip RBL checks for private or loopback addresses. Proceed with RBL checks for public IPs. ```perl sub filter_begin { my ($entity) = @_; unless (is_public_ip4_address($RelayAddr) || is_public_ip6_address($RelayAddr)) { md_syslog('info', "Skipping RBL checks for private/loopback relay $RelayAddr"); return; } # Now safe to do RBL checks if (relay_is_blacklisted($RelayAddr, 'zen.spamhaus.org')) { return action_bounce("Blacklisted IP"); } } ``` -------------------------------- ### action_notify_sender, action_notify_administrator Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Sends notification emails to the sender or administrator. ```APIDOC ## Notification Actions ### Description These actions send email notifications. `action_notify_sender` sends a message to the original sender of the email, typically to inform them about an action taken on their message. `action_notify_administrator` sends a message to the system administrator, providing details about security events or policy violations. ### Method Not applicable (function calls within a script) ### Endpoint Not applicable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```perl # Notify sender about a blocked attachment action_notify_sender("Your attachment '$fname' was removed because .exe files are blocked.\n"); # Notify administrator about a blocked .exe attachment action_notify_administrator("Blocked .exe attachment '$fname' from $Sender to " . join(", ", @Recipients) . "\n"); ``` ### Response #### Success Response (200) Not applicable (function return values indicate action success) #### Response Example Not applicable ``` -------------------------------- ### Verify DKIM Signatures Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use `md_dkim_verify()` to check DKIM signatures on incoming mail. It returns the verification result, domain, key size, and B tag. Add DKIM status headers and optionally bounce mail on failure. ```perl use Mail::MIMEDefang::DKIM; sub filter_end { my ($entity) = @_; my ($result, $domain, $keysize, $btag) = md_dkim_verify(); action_add_header("X-DKIM-Status", "result=$result; domain=$domain; keysize=$keysize"); if ($result eq "fail") { md_syslog('warning', "DKIM fail for domain $domain"); # Optionally bounce forged mail # return action_bounce("DKIM signature verification failed"); } } ``` -------------------------------- ### MIMEDefang filter_multipart Hook for Container MIME Parts Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt The filter_multipart hook is called for non-leaf (container) MIME parts. It acts on the container itself, and any action applies to all nested parts. It's crucial to check for dangerous filenames here as well, as malware can masquerade as containers. Ensure to return after calling an action. ```perl sub filter_multipart { my ($entity, $fname, $ext, $type) = @_; return if message_rejected(); if (lc($type) eq "message/partial") { return action_bounce("message/partial not accepted here"); } if (re_match($entity, '\.(exe|bat|com|scr)\.*$')) { action_notify_administrator( "Multipart attachment '$fname' of type '$type' was dropped.\n" ); return action_drop_with_warning( "Multipart attachment '$fname' removed for security reasons.\n" ); } return action_accept(); } ``` -------------------------------- ### Check if a message has already been rejected Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Uses `message_rejected()` to skip further processing if a bounce or temporary failure has already been issued. Returns `action_accept()` to allow the message to proceed. ```perl sub filter { my ($entity, $fname, $ext, $type) = @_; # Skip per-part work if bounce/tempfail already issued in filter_begin return if message_rejected(); return action_accept(); } ``` -------------------------------- ### action_sm_quarantine Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Quarantines a message using Sendmail's smfi_quarantine facility. ```APIDOC ## action_sm_quarantine ### Description Utilizes Sendmail's `smfi_quarantine` function to quarantine a message. This is a specific method for quarantining messages within a Sendmail environment. ### Method Not applicable (function call within a script) ### Endpoint Not applicable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```perl action_sm_quarantine("Virus: $VirusName"); ``` ### Response #### Success Response (200) Not applicable (function return value indicates action) #### Response Example Not applicable ``` -------------------------------- ### action_add_header, action_change_header, action_delete_header, action_delete_all_headers Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Manipulates message headers by adding, changing, or deleting them. ```APIDOC ## Header Manipulation Actions ### Description These actions provide granular control over email message headers. They allow for adding new headers, modifying existing ones, and removing headers entirely, including all occurrences of a specific header. ### Method Not applicable (function calls within a script) ### Endpoint Not applicable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```perl # Add a new trace header action_add_header("X-Filtered-By", "MIMEDefang 3.6"); # Change (replace) the subject prefix action_change_header("Subject", "[FILTERED] $Subject"); # Remove a header entirely action_delete_header("X-Originating-IP"); # Remove ALL occurrences of a header action_delete_all_headers("X-Mailer"); ``` ### Response #### Success Response (200) Not applicable (function return values indicate action success) #### Response Example Not applicable ``` -------------------------------- ### Check SPF Records Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use `md_spf_verify()` to check SPF records for sender and HELO identities. It returns codes and explanations for both. Add SPF result headers and bounce mail on SPF 'fail'. ```perl use Mail::MIMEDefang::SPF; sub filter_begin { my ($entity) = @_; my ($code, $exp, $helo_code, $helo_exp, $record) = md_spf_verify($Sender, $RelayAddr, $Helo); action_add_header("X-SPF-Result", "$code ($exp)"); if ($code eq "fail") { md_syslog('warning', "SPF fail for $Sender from $RelayAddr: $exp"); return action_bounce("SPF check failed: $exp", 550, "5.7.23"); } if ($code eq "softfail") { action_add_header("X-SPF-Warning", "softfail: $exp"); } } ``` -------------------------------- ### md_dkim_verify Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Verifies DKIM signatures on incoming mail. It returns the verification result, domain, key size, and b-tag. ```APIDOC ## md_dkim_verify — verify DKIM signatures on incoming mail ### Description Verifies DKIM signatures on incoming mail. Returns `($result, $domain, $key_size_bits, $b_tag)`. `$result` can be `'pass'`, `'fail'`, `'invalid'`, `'temperror'`, or `'none'`. ### Method Perl function call ### Parameters None explicitly documented for the function call itself, but it operates on the current email context. ### Response - **result** (string) - Verification status ('pass', 'fail', 'invalid', 'temperror', 'none'). - **domain** (string) - The domain associated with the DKIM signature. - **key_size_bits** (integer) - The size of the cryptographic key in bits. - **b_tag** (string) - The 'b' tag from the DKIM signature. ### Request Example ```perl use Mail::Mail::MIMEDefang::DKIM; sub filter_end { my ($entity) = @_; my ($result, $domain, $keysize, $btag) = md_dkim_verify(); action_add_header("X-DKIM-Status", "result=$result; domain=$domain; keysize=$keysize"); if ($result eq "fail") { md_syslog('warning', "DKIM fail for domain $domain"); # Optionally bounce forged mail # return action_bounce("DKIM signature verification failed"); } } ``` ### Response Example (Implicitly used within the `filter_end` subroutine) ``` -------------------------------- ### action_defang Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Renames and re-types a dangerous attachment to mitigate risk. ```APIDOC ## action_defang ### Description Modifies a dangerous attachment by renaming it and changing its MIME type. This action is designed to neutralize potential threats, such as executable files, by making them less likely to be executed. ### Method Not applicable (function call within a script) ### Endpoint Not applicable ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```perl action_defang($entity, "renamed-attachment", "$fname.defanged", "application/octet-stream"); ``` ### Response #### Success Response (200) Not applicable (function return value indicates action) #### Response Example Not applicable ``` -------------------------------- ### Email Blacklist (HASHBL) Lookup Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use `email_is_blacklisted()` for hash-based email blacklist lookups. Specify the sender address, blacklist domain, and hashing algorithm. Bounce mail if the sender address is blacklisted. ```perl sub filter_begin { my ($entity) = @_; # Check sender address hash against MSBL my $result = email_is_blacklisted($Sender, 'ebl.msbl.org', 'SHA1'); if ($result) { return action_bounce("Sender address is blacklisted", 550, "5.7.1"); } } ``` -------------------------------- ### Remove redundant HTML parts Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Strips 'text/html' parts from a multipart/alternative structure if a 'text/plain' part is also present, preventing redundant content display. ```perl sub filter_end { my ($entity) = @_; # Nuke HTML parts from multipart/alternative if plain text is present remove_redundant_html_parts($entity); } ``` -------------------------------- ### md_spf_verify Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Checks SPF records for sender and HELO identity. It returns codes and explanations for both the Mail From and HELO identities. ```APIDOC ## md_spf_verify — check SPF records for sender and HELO identity ### Description Checks SPF records for the sender (Mail From) and HELO identity. Returns `($mfrom_code, $mfrom_explanation, $helo_code, $helo_explanation, $spf_record, $helo_record)`. ### Method Perl function call ### Parameters - **Sender** (string) - The sender's email address. - **RelayAddr** (string) - The IP address of the connecting client. - **Helo** (string) - The HELO/EHLO string provided by the connecting client. ### Response - **mfrom_code** (string) - The SPF result code for the Mail From identity. - **mfrom_explanation** (string) - An explanation for the Mail From SPF result. - **helo_code** (string) - The SPF result code for the HELO identity. - **helo_explanation** (string) - An explanation for the HELO SPF result. - **spf_record** (string) - The SPF record found for the sender's domain. - **helo_record** (string) - The SPF record found for the HELO domain. ### Request Example ```perl use Mail::Mail::MIMEDefang::SPF; sub filter_begin { my ($entity) = @_; my ($code, $exp, $helo_code, $helo_exp, $record) = md_spf_verify($Sender, $RelayAddr, $Helo); action_add_header("X-SPF-Result", "$code ($exp)"); if ($code eq "fail") { md_syslog('warning', "SPF fail for $Sender from $RelayAddr: $exp"); return action_bounce("SPF check failed: $exp", 550, "5.7.23"); } if ($code eq "softfail") { action_add_header("X-SPF-Warning", "softfail: $exp"); } } ``` ### Response Example (Implicitly used within the `filter_begin` subroutine) ``` -------------------------------- ### Anonymize URIs by stripping tracking parameters Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Removes UTM tracking parameters (e.g., `?utm_source=...`) from all URLs found within text-based MIME parts of an email. ```perl sub filter_end { my ($entity) = @_; # Remove ?utm_source=...&utm_campaign=... from all text/* parts anonymize_uri($entity); } ``` -------------------------------- ### Insert Header at Specific Position - MIMEDefang Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Use to insert a header at a specific position within the message headers. Position 0 inserts it as the very first header. ```perl sub filter_end { my ($entity) = @_; # Insert as the very first header (position 0) action_insert_header("X-MIMEDefang-Scanned", "yes", 0); } ``` -------------------------------- ### md_syslog Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Writes messages to the system log (syslog) from within the filter. ```APIDOC ## md_syslog — write to syslog from within the filter ### Description Logs messages to the system log. It automatically prepends the current message queue ID (if available) to the log entry for easier correlation. ### Method Perl function call ### Parameters - **priority** (string) - The log priority level (e.g., 'info', 'warning', 'err'). - **message** (string) - The message string to log. ### Response None. This function performs a side effect (logging). ### Request Example ```perl # Automatically prepends the queue ID ($MsgID) when available md_syslog('info', "Processing message from $Sender"); md_syslog('warning', "Suspicious attachment: $fname"); md_syslog('err', "Virus scanner failed with code $code"); ``` ### Response Example (Log entries written to syslog) ``` -------------------------------- ### email_is_blacklisted Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Performs a hash-based lookup against an email blacklist (HASHBL) for a given email address. ```APIDOC ## email_is_blacklisted — hash-based email blacklist (HASHBL) lookup ### Description Performs a hash-based lookup against a specified HASHBL for a given email address. Returns a truthy value if the email address hash is found in the blacklist, and a falsy value otherwise. ### Method Perl function call ### Parameters - **email_address** (string) - The email address to check. - **hashbl_domain** (string) - The domain name of the HASHBL to query (e.g., 'ebl.msbl.org'). - **hash_type** (string) - The type of hash to use (e.g., 'SHA1'). ### Response - **result** (string or undef) - If the email address hash is blacklisted, returns a string containing DNS lookup details; otherwise, returns `undef`. ### Request Example ```perl sub filter_begin { my ($entity) = @_; # Check sender address hash against MSBL my $result = email_is_blacklisted($Sender, 'ebl.msbl.org', 'SHA1'); if ($result) { return action_bounce("Sender address is blacklisted", 550, "5.7.1"); } } ``` ### Response Example (Implicitly used within the `filter_begin` subroutine) ``` -------------------------------- ### action_bounce Source: https://context7.com/the-mcgrail-foundation/mimedefang/llms.txt Rejects the entire message with a permanent SMTP error (5xx). This is used for critical rejections, such as when a sender's IP is blacklisted. ```APIDOC ## action_bounce ### Description Reject the entire message with a permanent SMTP error. ### Parameters * `reason` (string) - The reason for the bounce. * `smtp_code` (integer) - The SMTP status code (e.g., 554). * `smtp_enhanced_code` (string) - The enhanced SMTP status code (e.g., "5.7.1"). ### Usage in filter_begin ```perl sub filter_begin { my ($entity) = @_; # Reject if relay is on Spamhaus if (relay_is_blacklisted($RelayAddr, 'zen.spamhaus.org')) { return action_bounce( "Your IP $RelayAddr is listed in Spamhaus ZEN.", 554, "5.7.1" ); } } ``` ```