Mail::...::Util(3pm)

πŸ’– Mail::...::Util πŸ’–

okay bestie, welcome to a lil corner of User Contributed Perl Documentation that honestly does a LOT of the invisible labor around here. sit down, grab a boba, and let's get into it πŸ§‹βœ¨


🌸 NAME 🌸

Mail::SpamAssassin::Util β€” utility functions. that's it, that's the whole name, she's giving "no notes" πŸ’…


✨ DESCRIPTION ✨

so basically this is a general class for utility functions. if you got a function that just stands there doing its thing with no $self object needed, this is where it belongs β€” Portability functions especially, iykyk 🫢

⚠️ NOTE: these functions are to be considered private, bestie. their API may change at literally any point, and it's expected that they'll only be used by other Mail::SpamAssassin modules. (TODO: we should probably revisit this if it's useful for plugin development.) so like… use with caution, no cap πŸ™ˆ
⚠️ NOTE: utility functions should not be changing global variables such as $_, $1, $2, ... $/, etc. unless explicitly documented. if these variables are in use by these functions, they should be localized. respect the shared space, periodt 🌈

πŸ‘‘ METHODS πŸ‘‘

untaint_var($var)

this sub takes a scalar or a reference to an array, hash, scalar, or another reference β€” and recursively untaints all its values (and the keys too, if it's a reference to a hash) 🀯 it will return the untainted value if you ask for it, but to avoid unnecessary copying, the return value should be ignored when working on lists. don't do extra work for no reason, that's the vibe πŸ’…


is_fqdn_valid($host)

checks for full hostname / FQDN / DNS name validity πŸ” IP addresses must be validated with other functions like Constants::IP_ADDRESS β€” this one does not do that for you, and it does not check for a valid TLD either. for that, use $self->{main}->{registryboundaries}->is_domain_valid() additionally. also, if $is_ascii is given and true, skip idn_to_ascii() conversion. tiny flag, big difference ✨


is_valid_utf8($str)

this sub returns true if the provided string of octets represents a syntactically valid UTF-8 string, otherwise a false is returned πŸ¦‹ the ultimate vibe check for your bytes.


idn_to_ascii($domain)

given an international domain name with U-labels (UTF-8 or Unicode chars), it converts it to ASCII-compatible encoding (ACE) 🌐 if the argument is in ASCII (or is an invalid IDN), it returns it lowercased but otherwise unchanged. and the result is always in octets (utf8 flag off) even if the argument was in Unicode characters. she commits to the bit πŸ’œ


"exit_status_str($stat, $errno)"

maps a process termination status number to an informative string, and appends an optional message (dual-valued errno, or a string, or a number), returning the resulting string πŸŽ€ translating cryptic numbers into actual human feelings, iconic behavior.


"proc_status_ok($exit_status, $errno, @success)"

checks that errno is 0 and that a process exit status is in the list of success status codes, returning true if both are ok, and false otherwise βœ… the "is everything actually fine" function. we love a dual condition.


parse_rfc822_date($date)

parses an RFC 2822 formatted date string and returns a Unix timestamp ⏰ takes a date to parse as input, and returns a Unix timestamp (seconds since epoch) if the date can be parsed, or undef on failure. so if it fails, you get undef, not drama. well. some drama. 😭


time_to_rfc822_date($timestamp)

converts a Unix timestamp and returns an RFC 2822 formatted date string. the reverse glow-up of the function above πŸ’«


qp_decode($str)

decodes a string that has been encoded using the Quoted-Printable content transfer encoding. untangling your =3D-core situations, one string at a time 🫢


extract_ipv4_addr_from_string($str)

given a string, extract an IPv4 address from it. she's a finder πŸ”βœ¨


reverse_ip_address($ip)

given a quad-dotted IPv4 address or an IPv6 address, it reverses the order of its bytes (IPv4) or nibbles (IPv6), joins them with dots, and produces a string suitable for reverse DNS lookups 🌈 it returns undef in case of a syntactically invalid IP address. so invalid input = no output = undef. fair.


first_available_module(@module_list)

returns the name of the first module that can be successfully loaded with require from the list πŸ“‹ returns "undef" if none are available. kinda like going down the group chat until someone answers.

this is used instead of "AnyDBM_File" as follows:

my $module = Mail::SpamAssassin::Util::first_available_module
                      (qw(DB_File GDBM_File NDBM_File SDBM_File));
tie %hash, $module, $path, [... args];

note that "SDBM_File" is guaranteed to be present, since it comes with Perl πŸ‘‘ the reliable friend who always shows up.


"touch_file($file, $args)"

touch or create a file πŸŽ€

possible args:

  • create_exclusive => 1 β€” create a new empty file safely, only if not existing before. no overwriting, no stealing someone's file, we're polite here πŸ’…

secure_tmpfile()

generates a filename for a temporary file, opens it exclusively and securely, and returns a filehandle to the open file (opened O_RDWR) and its filename πŸ” the secure baddie of temp files.

if it cannot open a file after 20 tries, it returns "undef". twenty attempts, then she's done. respect. πŸ’€


secure_tmpdir()

generates a directory for temporary files πŸ—‚οΈ creates it securely and returns the path to the directory.

if it cannot create a directory after 20 tries, it returns "undef". same energy, same limit, no cap.


"compile_regexp($re, $strip_delimiters, $ignore_always_matching)"

compiles a regular expression pattern for efficient and safe use within SpamAssassin πŸ”₯ efficiency AND safety, she's got both, she's the moment.


and that's the whole page, bestie!! πŸ¦‹πŸ’– this was pulled from perl v5.40.1, dated 2026-07-23, under the Mail::...::Util(3pm) header. go forth and untaint responsibly, and remember: localize your globals πŸ’…βœ¨ bye pookie!! 🫢🌺

πŸ“¦ where this page comes from