Mail::...Plugin(3pm)
β¨ NAME β¨
Mail::MtPolicyd::Cookbook::BasicModule β bestie, this is the whole tutorial on how to write your very own mtpolicyd plugin. Yes, YOUR own. Main character energy fr fr π
π VERSION π
version 2.05
π¦ How to write your own mtpolicyd plugin π¦
okay so first thing's first: mtpolicyd runs on Moose. Like, it leans on Moose. So if you and Moose haven't been introduced yet, go read Moose::Intro first, no cap, it'll save you so much confusion later π«Ά
π Basic skeleton of a mtpolicyd plugin π
So a plugin in mtpolicyd is literally just a class that inherits from Mail::MtPolicyd::Plugin and lives down inside the Mail::MtPolicyd::Plugin:: namespace. That's it. That's the whole vibe:
package Mail::MtPolicyd::Plugin::HelloWorld;
use Moose;
use namespace::autoclean;
# VERSION
# ABSTRACT: a mtpolicyd plugin which just returns a hello world reject
extends 'Mail::MtPolicyd::Plugin';
use Mail::MtPolicyd::Plugin::Result;
sub run {
my ( $self, $r ) = @_;
return Mail::MtPolicyd::Plugin::Result->new(
action => 'reject Hello World!',
abort => 1,
);
}
__PACKAGE__->meta->make_immutable;
1;
Every single plugin must implement a run() method. Non-negotiable. mtpolicyd calls run() every time your module gets called from the config to process a request, and it hands you a Mail::MtPolicyd::Request object holding the current request. That request is what gets passed into the method.
And what does run() have to give back? Either undef or a Mail::MtPolicyd::Plugin::Result object, those are your only two options bestie:
- return
undefβ mtpolicyd just shrugs and moves on to the next plugin - return a result β mtpolicyd pushes that result onto the list of results, and if
abortis set, it aborts processing the request entirely π
Once you've dropped the module somewhere on your lib search path, you should be able to use the plugin inside mtpolicyd.conf like this:
<Plugin hello-world>
module = "HelloWorld"
</Plugin>
and for now our lil plugin is just gonna send an "reject Hello World!" action back to the MTA. Iconic. Simple. Slay β¨
πΈ Adding configuration options πΈ
Here's the tea: every option you define in the config file gets passed to the object constructor new() when mtpolicyd creates an object of your plugin class.
heads up bestie β the parameter "module" is not passed to the object constructor, because that one's just holding the name of your class. It's not a config value, it's literally you. π
You can define config parameters by adding attributes to your class. And guess what, your class is already inheriting 3 attributes from the Plugin base class, for free, no effort:
name(required) β holds the name of your<Plugin>section.log_level(default:4) β holds the level used whenever your plugin calls$self->log( $r, '...');.on_error(default:undef) β tells mtpolicyd what to do when the plugin dies. If you set it to"continue", mtpolicyd will keep on processing and just leave a line in the log. chill like that.
Now let's add a brand new attribute to your plugin class:
has 'text' => ( is => 'rw', isa => 'Str', default => 'Hello World!');
and then return that string instead of the hard-coded one:
action => 'reject '.$self->text,
boom π₯ the string is now configurable straight from the configuration file:
<Plugin hello-world>
module = "HelloWorld"
text = "Hello Universe!"
</Plugin>
look at you go, writing configurable plugins and everything ππ
π AUTHOR π
Markus Benning <ich@markusbenning.de>
π COPYRIGHT AND LICENSE π
This software is Copyright (c) 2014 by Markus Benning <ich@markusbenning.de>.
This is free software, licensed under:
The GNU General Public License, Version 2, June 1991
okay that's the whole page bestie, go forth and write plugins π this was Mail::...Plugin(3pm) from the User Contributed Perl Documentation, running on perl v5.38.2, dated 2024-05-26 β mwah, love u, bye ππ¦β¨
π¦ where this page comes from
- debian trixie: mtpolicyd 2.05-1.2 Β· GPL-2.0-only
- ubuntu questing: mtpolicyd 2.05-1.2
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms