Mail::...rectors(3pm)
β¨ NAME β¨
okay so bestie, welcome to <pink>Mail::...rectors(3pm)</pink> β it's part of the User Contributed Perl Documentation, and it's literally the page for the Redirectors plugin: the thing that checks for redirected URLs. that's it, that's the whole vibe check. π
πΈ SYNOPSIS πΈ
here's the whole starter pack, copy-paste style, no notes:
loadplugin Mail::SpamAssassin::Plugin::Redirectors
url_redirector bing.com
body HAS_REDIR_URL eval:redir_url()
describe HAS_REDIR_URL Message has one or more redirected URLs
body REDIR_URL_VALID eval:redir_url_valid()
describe REDIR_URL_VALID Message has a redirector that returned a valid redirection
body REDIR_URL_CHAINED eval:redir_url_chained()
describe REDIR_URL_CHAINED Message has redirected URL chained to other redirectors
body REDIR_URL_CHAINED_DOM eval:redir_url_chained_domain()
describe REDIR_URL_CHAINED_DOM Message has redirected URL chained to another redirector on the same domain
body REDIR_URL_MAXCHAIN eval:redir_url_maxchain()
describe REDIR_URL_MAXCHAIN Message has redirected URL that causes too many redirections
body REDIR_URL_LOOP eval:redir_url_loop()
describe REDIR_URL_LOOP Message has redirected URL that loops back to itself
body REDIR_URL_404 eval:redir_url_code('404') # Can check any non-redirect HTTP code
describe REDIR_URL_404 Message has redirected URL returning HTTP 404
π¦ DESCRIPTION π¦
so this plugin is out here looking for URLs that got redirected by a whole list of URL redirector services. the moment it finds a URL that matches, it sends an HTTP request off to the redirector service and grabs the Location-header, which points at the actual redirected URL. then it drops that URL into the list of URIs that SpamAssassin already extracted, so uri rules and plugins like URIDNSBL can get their hands on it. icons only fr π«Ά
it also follows chained redirections β that's when a redirected URL redirects to another redirector. the depth limit for that is set with max_redir_url_redirections.
a maximum of max_redir_urls redirected URLs get checked per message (that's 10 by default btw). set it to 0 and HTTP requests are fully off, which means only the redir_url() test keeps working and reporting the redirectors it found.
every single supported rule type for checking redirector URLs and redirection status is documented right up in the SYNOPSIS β go look, it's all there. β¨
π NOTES π
this plugin runs before priority 0 so it can modify the parsed URI list before the normal uri rules or the URIDNSBL plugin ever see it. and it should run before the DecodeShortURLs plugin, so that redirected short uris get checked too. literally sequencing matters, iykyk. π
π USER SETTINGS π
url_redirector domain[/path] [domain[/path]...]β default: none. these are the domains that should be treated as a URL redirector. π
domain matching, bestie, listen up:
- a bare domain (like
bing.com) matches that exact host and alsowww.bing.com. - a leading dot (like
.sendgrid.com) matches any subdomain of the domain, to any depth. it does NOT match the bare domain itself β so if you want both, list the bare domain too (sendgrid.com).
an optional /path can follow the domain, and it restricts matching to URLs whose path begins with that string and ends at a path-segment boundary. /tr/op matches /tr/op, /tr/op/foo, and /tr/op?x=1, but NOT /tr/open β because the configured prefix is treated as one or more whole path segments. append a trailing slash (/tr/op/) if you want to require at least one more segment after it (that matches /tr/op/foo but not bare /tr/op). multiple entries for the same domain are additive (allowlist); a URL gets followed if it matches any entry.
a bare-domain entry without a path is equivalent to domain/, which matches any path.
example, slay:
url_redirector bing.com
url_redirector .sendgrid.com
url_redirector .sendibt2.com/tr/cl/
the last line follows https://x.y.sendibt2.com/tr/cl/abc but not https://x.y.sendibt2.com/tr/op/abc. periodt. π
url_redirector_use_seleniumβ default: 0. turns on the Selenium subsystem. when it's1, hosts listed inurl_redirector_seleniumget fetched using Selenium (headless Chrome). when it's0(the default), those hosts are skipped entirely β and nope, there is no fallback to LWP, because hosts only belong inurl_redirector_seleniumif their redirects can't be discovered via LWP (like JavaScript-driven redirects, ugh).
this is a runtime kill switch: an operator can disable the Selenium subsystem without touching the host allowlist. while it's off, those hosts just don't get probed β but redir_url() still fires for them, so detection rules keep working. π«Ά
heads up: because of how Selenium works,redir_url_code()and theredir_url_404subs will not fire for hosts handled by Selenium. Selenium only reports "redirected" (301) or "not a redirect" (200) β not real HTTP status codes.
url_redirector_selenium_hostβ default: 127.0.0.1. set the Selenium host to use.url_redirector_selenium_portβ default: 4444. set the Selenium port to use.clear_url_redirector [domain[/path]] [domain[/path]...]β clear the configuredurl_redirectordomains, like if you wanna override default settings from an update channel. give it no arguments and all entries get cleared. name some domains and only those get removed. π§Ή
when an entry includes a /path, only that path is removed from that domain's allowlist β and the domain entry itself is only dropped once its path list is empty. use domain/ to remove the "match any path" entry that a bare-domain config added.
url_redirector_get domain[/path] [domain[/path]...]β default: none. domains that should be considered an URL redirector, accessed using the HTTP GET method instead of HEAD. syntax and matching rules are the same asurl_redirector: bare domain matches that host andwww., a leading dot matches the domain and any subdomain, and an optional/pathprefix restricts the match.url_redirector_selenium domain[/path] [domain[/path]...]β default: none. domains that should be fetched using Selenium (headless Chrome) instead of LWP. only use this for hosts whose redirects are NOT discoverable via LWP, like JavaScript-driven redirects. syntax and matching rules are the same asurl_redirector.
real talk: Selenium executes JavaScript on the destination and always sends GET, which has weaker safety properties than the LWP path β so reserve this list for hosts that genuinely require browser-driven redirect unwrapping. π
if the same host shows up in both url_redirector_selenium and url_redirector/url_redirector_get, the directive parsed last sets the method, and a warning gets emitted.
the Selenium subsystem is gated by url_redirector_use_selenium. when that flag is off, hosts in this list are skipped entirely (no fallback to LWP, since these hosts wouldn't yield useful results via LWP anyway).
url_skip_redirect_to domain [domain...]β default: none. domains that, when found as a redirect destination, should cause the redirect chain to stop immediately. super useful for breaking loops caused by consent or gateway pages that redirect back into the chain. π₯
example:
url_skip_redirect_to consent.google.com
clear_url_skip_redirect_to [domain] [domain...]β clear configuredurl_skip_redirect_todomains. if you name domains, only those get removed from the list.url_redirector_params regexpβ default:(?:adurl|af_web_dp|cm_destination|continue|destination|destURL|goto|h|l|login|location|p1|pval|r|redir|redirect|redirectTo|return|returnUrl|referer|service|target|tid|u|url)=(.*). the regexp used to parse uri parameters so it can detect redirectors and get redirected domains. the regexp must match only the redirected domain.
π PRIVILEGED SETTINGS π
url_redirector_cache_typeβ default: none. the cache type being utilized. right now the only supported value isdbi, which impliesurl_redirector_cache_dsnis a DBI connect string. and yes, the DBI module is required. β¨
example: url_redirector_cache_type dbi
url_redirector_cache_dsnβ default: none. the DBI dsn of the database to use.
for SQLite, the database gets created automatically if it doesn't already exist, and the supplied path and file must be read/writable by the user running spamassassin or spamd.
for MySQL/MariaDB or PostgreSQL, check out sql-directory for the database table creation clauses.
you're gonna need the proper DBI module for your database. like DBD::SQLite, DBD::mysql, DBD::MariaDB or DBD::Pg.
minimum required SQLite version is 3.24.0 (available from DBD::SQLite 1.59_01).
examples:
url_redirector_cache_dsn dbi:SQLite:dbname=/var/lib/spamassassin/Redirectors.db
url_redirector_cache_usernameβ default: none. the username that should be used to connect to the database. not used for SQLite.url_redirector_cache_passwordβ default: none. the password that should be used to connect to the database. not used for SQLite.url_redirector_cache_ttlβ default: 86400. how long a cache entry stays valid for, in seconds. default is 86400 (that's 1 day, bestie). seeurl_redirector_cache_autocleanfor database cleaning. π§
β ADMINISTRATOR SETTINGS β
url_redirector_cache_autocleanβ default: 1000. automatically purge old entries from the database. the value describes a random run chance of 1/x. the default value of 1000 means cleaning runs approximately once for every 1000 messages processed. a value of 1 would mean the database is cleaned every single time a message is processed. π
set it to 0 to disable automatic cleaning and do it manually instead.
url_redirector_loginfoβ default: 0 (off). if this option is enabled (set to1), then redirected URLs and the decoded URLs get logged with info priority.url_redirector_timeoutβ default: 5. maximum time a redirection URL HTTP request can take, in seconds.max_redir_urlsβ default: 10. maximum amount of redirector URLs that will be looked up per message. chained redirections are not counted β only the initial redirection URLs found.
setting it to 0 disables HTTP requests, letting only the redir_url() test work and report any found redirector URLs.
max_redir_url_redirectionsβ default: 10. maximum depth of chained redirections that a redirector can generate.url_redirector_user_agentβ default:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36. sets theUser-Agentheader for HTTP requests. some services require it to look like a common browser, no cap. π
and that's the whole page, bestie!! this was perl v5.40.1, dated 2026-07-23, straight out of the <pink>Mail::...rectors(3pm)</pink> page in the User Contributed Perl Documentation. go forth and de-redirect, you absolute icon. ππ¦π
π¦ where this page comes from
- ubuntu stonking: spamassassin 4.0.2+svn1935691-1build1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms