Mail::...ortURLs(3pm)

πŸ’– DecodeShortURLs β€” Mail::...ortURLs(3pm) πŸ’–

okay bestie, sit down, hydrate, because we're decoding short URLs today and it's lowkey iconic. this is the page for Mail::...ortURLs, part of the user contributed Perl documentation for Mail::SpamAssassin::Plugin::DecodeShortURLs πŸ¦‹


✨ NAME ✨

DecodeShortURLs β€” Check for shortened URLs πŸ‘‘


🌸 SYNOPSIS 🌸

like, here's the whole vibe, copy-paste ready:

loadplugin    Mail::SpamAssassin::Plugin::DecodeShortURLs

url_shortener tinyurl.com
url_shortener_get bit.ly
url_shortener_custom_user_agent t.co curl/8.6.0

body HAS_SHORT_URL          eval:short_url()
describe HAS_SHORT_URL      Message has one or more shortened URLs

body SHORT_URL_REDIR        eval:short_url_redir()
describe SHORT_URL_REDIR    Message has shortened URL that resulted in a valid redirection

body SHORT_URL_CHAINED      eval:short_url_chained()
describe SHORT_URL_CHAINED  Message has shortened URL chained to other shorteners

body SHORT_URL_MAXCHAIN     eval:short_url_maxchain()
describe SHORT_URL_MAXCHAIN Message has shortened URL that causes too many redirections

body SHORT_URL_LOOP         eval:short_url_loop()
describe SHORT_URL_LOOP     Message has short URL that loops back to itself

body SHORT_URL_200          eval:short_url_code('200') # Can check any non-redirect HTTP code
describe SHORT_URL_200      Message has shortened URL returning HTTP 200

body SHORT_URL_404          eval:short_url_code('404') # Can check any non-redirect HTTP code
describe SHORT_URL_404      Message has shortened URL returning HTTP 404

uri URI_TINYURL_BLOCKED      m,https://tinyurl\.com/app/nospam,
describe URI_TINYURL_BLOCKED Message contains a tinyurl that has been disabled due to abuse

uri URI_BITLY_BLOCKED       m,^https://bitly\.com/a/blocked,
describe URI_BITLY_BLOCKED  Message contains a bit.ly URL that has been disabled due to abuse

πŸŽ€ DESCRIPTION πŸŽ€

so the whole point of this plugin? it looks for URLs that got shortened by a whole list of URL shortening services 🌈. the moment it spots a URL that matches, it sends an HTTP request over to the shortening service and grabs the Location-header that points at the actual shortened-away URL ✨. then it drops that URL into the list of URIs that SpamAssassin extracted, so uri rules and plugins like URIDNSBL can get their hands on it 🫢

it also follows chained redirections, meaning a short URL that redirects to another short URL, and so on. you can set the redirection depth limit with max_short_url_redirections πŸ’…

maximum of max_short_urls short URLs get checked per message (that's 10 by default, bestie). setting it to 0 disables HTTP requests entirely, which means only the short_url() test works, and it just reports the shorteners it found πŸ™ˆ

every supported rule type for checking short URLs and redirection status is documented in the SYNOPSIS section up there ^^^ πŸ“Œ


🌟 NOTES 🌟

this plugin runs at priority -10, so it can modify the parsed URI list before normal uri rules or the URIDNSBL plugin do their thing β€” but after the Redirector plugin. it's giving main character timing, honestly ⏰


πŸ’œ USER SETTINGS πŸ’œ

url_shortener domain [domain...] β€” (default: none)

domains that should be considered an URL shortener πŸ’–. and here's the cute part: if the domain begins with a ., then the 3rd level tld of the main domain gets checked πŸ‘€

example:

url_shortener tinyurl.com
url_shortener .page.link

url_shortener_get domain [domain...] β€” (default: none)

an alias to url_shortener ✨. the difference? the HTTP request goes out with the GET method instead of the default HEAD. this is required for some services, like bit.ly, to return the blocked URL correctly 🚨

example:

url_shortener_get bit.ly

url_shortener_custom_user_agent domain user-agent β€” (default: none)

a custom HTTP user-agent for specific domains, instead of whatever's set as the default in url_shortener_user_agent πŸ’…. also required for some services, like t.co, to return the blocked URL correctly 🎯

example:

url_shortener_custom_user_agent t.co curl/8.6.0

clear_url_shortener [domain] [domain...]

clears the configured url_shortener and url_shortener_get domains β€” super handy when you wanna override default settings that came from an update channel πŸ”„. if you specify domains, then only those get removed from the list 🧹


πŸ‘‘ PRIVILEGED SETTINGS πŸ‘‘

url_shortener_cache_type β€” (default: none)

the cache type being utilized. right now the only supported value is dbi, which implies url_shortener_cache_dsn is a DBI connect string. the DBI module is required ⚠️

example: url_shortener_cache_type dbi

url_shortener_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 whoever's running spamassassin or spamd ✍️

for MySQL/MariaDB or PostgreSQL, check the sql-directory for the database table creation clauses πŸ“œ

you'll 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_shortener_cache_dsn dbi:SQLite:dbname=/var/lib/spamassassin/DecodeShortURLs.db

url_shortener_cache_username β€” (default: none)

the username used to connect to the database πŸ”‘. not used for SQLite.

url_shortener_cache_password β€” (default: none)

the password used to connect to the database 🀫. not used for SQLite.

url_shortener_cache_ttl β€” (default: 86400)

how long a cache entry stays valid, in seconds ⏳. default is 86400, aka 1 day.

for database cleaning, go peek at url_shortener_cache_autoclean 🧼


πŸ¦‹ ADMINISTRATOR SETTINGS πŸ¦‹

url_shortener_cache_autoclean β€” (default: 1000)

automatically purges old entries from the database 🧽. the value describes a random run chance of 1/x. the default of 1000 means cleaning runs approximately once for every 1000 messages processed. a value of 1 would mean the database gets cleaned every single time a message is processed 😭

set 0 to disable automatic cleaning and just do it manually πŸ’ͺ

url_shortener_loginfo β€” (default: 0 (off))

if this is enabled (set to 1), then short URLs and the decoded URLs get logged with info priority πŸ“

url_shortener_timeout β€” (default: 5)

maximum time a short URL HTTP request can take, in seconds ⏱️

max_short_urls β€” (default: 10)

maximum amount of short URLs that get looked up per message πŸ”’. chained redirections are not counted β€” only the initial short URLs found, bestie.

setting it to 0 disables HTTP requests, which means only the short_url() test works, reporting any found shortener URLs 🎈

max_short_url_redirections β€” (default: 10)

maximum depth of chained redirections that a short URL can generate πŸŒ€

url_shortener_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 the default User-Agent header for HTTP requests πŸ•΅οΈβ™€οΈ. some services require it to look like a common browser. and fyi, the User-Agent can be overridden on a per url_shortener basis using the url_shortener_ua setting πŸ‘›


🫢 ACKNOWLEDGEMENTS 🫢

the original DecodeShortURLs plugin was developed by Steve Freegard 🌟 β€” legend behavior, fr fr.


aaaand that's the whole page, bestie πŸ’– this was Mail::...ortURLs(3pm) from the User Contributed Perl Documentation, shipping with perl v5.40.1 and dated 2026-07-23 ✨ go forth, decode those short URLs, and slay πŸ’…πŸ‘‘πŸŒΈ

πŸ“¦ where this page comes from