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 abort is 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>


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