.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" ======================================================================== .\" .IX Title "Mail::MtPolicyd::Cookbook::ExtendedPlugin 3pm" .TH Mail::MtPolicyd::Cookbook::ExtendedPlugin 3pm "2017-01-13" "perl v5.24.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Mail::MtPolicyd::Cookbook::ExtendedModule \- how to archieve certain tasks within a plugin .SH "VERSION" .IX Header "VERSION" version 2.02 .SH "Extending your mtpolicyd plugin" .IX Header "Extending your mtpolicyd plugin" How to archieve common task within your plugin. .SS "Logging" .IX Subsection "Logging" You can output log messages to the mail.log from within your plugin by calling: .PP .Vb 1 \& $self\->log( $r, \*(Aq\*(Aq ); .Ve .PP The \fIlog()\fR method is inherited from the Plugin base class. .PP The default log_level used is 4. .PP To debug your plugin you can overwrite the log_level in your plugins configuration: .PP .Vb 4 \& \& module = "HelloWorld" \& log_level = 2 \& .Ve .PP This will cause your plugin to log with an higher log_level of 2. .SS "Caching lookup results" .IX Subsection "Caching lookup results" If your plugin is called from the smtpd_recipient_restrictions if will be called once for every recipient. If your plugin does an lookup (dns, database, ...) should cache the result. .PP The Mail::MtPolicyd::Request object implements the method \fIdo_cached()\fR to archieve this: .PP .Vb 2 \& my ( $ip_result, $info ) = $r\->do_cached(\*(Aqrbl\-\*(Aq.$self\->name.\*(Aq\-result\*(Aq, \& sub { $self\->_rbl\->check( $ip ) } ); .Ve .PP The first parameter is the key in the session to store the cached result. The second parameter is a function reference. .PP It will check if theres already an result stored in the given key within the session. In this case it will return the cached result as an array. If there is no result it will execute the code reference, store the result within the session and will also return an array containing the return values of the result. .SS "Doing things only once per mail" .IX Subsection "Doing things only once per mail" If your plugin is called from the smtpd_recipient_restrictions if will be called once for every recipient but some tasks should only be performed once per mail. .PP The Mail::MtPolicyd::Request object implements the method \fIis_already_done()\fR to archieve this: .PP .Vb 3 \& if( defined $self\->score && ! $r\->is_already_done( $self\->name.\*(Aq\-score\*(Aq ) ) { \& $self\->add_score($r, $self\->name => $self\->score); \& } .Ve .PP The method takes the key in the session in which the flag is stored. .PP The example above will add a new score to the scoring, but only once per mail since the session is persisted across different checks. .SS "Use scoring" .IX Subsection "Use scoring" To add scoring to your plugin your plugin needs to consume the role Mail::MtPolicyd::Plugin::Role::Scoring. .PP This will add the method add_score( \f(CW$r\fR, \f(CW$key\fR, \f(CW$value\fR ) to your plugin class. .PP The \f(CW$key\fR is a name for the score you'll see when you display the detailed scores. eg. with the AddScoreHeader or ScoreAction plugin. .PP The \f(CW$value\fR is positive or negative number. In most cases you want to make this value configurable. .PP It is also recommended that you check that you add an score only once. See \fIis_already_done()\fR method above. .PP Here is an example: .PP .Vb 1 \& with \*(AqMail::MtPolicyd::Plugin::Role::Scoring\*(Aq; \& \& has \*(Aqscore\*(Aq => ( is => \*(Aqrw\*(Aq, isa => \*(AqMaybe[Num]\*(Aq ); .Ve .PP And somewhere in your \fIrun()\fR method: .PP .Vb 3 \& if( defined $self\->score && ! $r\->is_already_done( $self\->name.\*(Aq\-score\*(Aq ) ) { \& $self\->add_score( $r, $self\->name => $self\->score ); \& } .Ve .SS "Make a configuration value user-configurable" .IX Subsection "Make a configuration value user-configurable" To add user configurable parameters to your plugin the class must consume the Mail::MtPolicyd::Plugin::Role::UserConfig role. .PP .Vb 3 \& with \*(AqMail::MtPolicyd::Plugin::Role::UserConfig\*(Aq => { \& \*(Aquc_attributes\*(Aq => [ \*(Aqenabled\*(Aq, \*(Aqmode\*(Aq ], \& }; .Ve .PP The regular attributes: .PP .Vb 2 \& has \*(Aqenabled\*(Aq => ( is => \*(Aqrw\*(Aq, isa => \*(AqStr\*(Aq, default => \*(Aqon\*(Aq ); \& has \*(Aqmode\*(Aq => ( is => \*(Aqrw\*(Aq, isa => \*(AqStr\*(Aq, default => \*(Aqreject\*(Aq ); .Ve .PP The UserConfig role adds the get_uc( \f(CW$session\fR, \f(CW$param\fR ) method to your class. To retrieve the user-configurable values for this attributes use: .PP .Vb 3 \& my $session = $r\->session; \& my $mode = $self\->get_uc( $session, \*(Aqmode\*(Aq ); \& my $enabled = $self\->get_uc( $session, \*(Aqenabled\*(Aq ); .Ve .PP Per user configuration in mtpolicyd works like this: .IP "Retrieve configuration values and store them in the session" 4 .IX Item "Retrieve configuration values and store them in the session" A plugin like SqlUserConfig retrieves configuration values and stores them in the current session. .Sp For example it may set the following key value: .Sp .Vb 1 \& hello_world_enabled = off .Ve .IP "A Plugin with user configurable parameters" 4 .IX Item "A Plugin with user configurable parameters" Our HelloWorld plugin may be configured like this: .Sp .Vb 5 \& \& module = "HelloWorld" \& enabled = on \& uc_enabled = "hello_world_enabled" \& .Ve .Sp If the key \*(L"hello_world_enabled\*(R" is defined in the session it will use its value for \f(CW$mode\fR. If it is not defined it will fall back to value of the \*(L"enabled\*(R" attribute. .SS "Set a mail header" .IX Subsection "Set a mail header" The Mail::MtPolicyd::Plugin::Result object has an extra constructor for returning a \s-1PREPEND\s0 action for setting a header: .PP .Vb 1 \& Mail::MtPolicyd::Plugin::Result\->new_header_once( $is_already_done, $header_name, $value ); .Ve .PP It could be used like this: .PP .Vb 3 \& return Mail::MtPolicyd::Plugin::Result\->new_header_once( \& $r\->is_already_done( $self\->name.\*(Aq\-tag\*(Aq ), \& $header_name, $value ); .Ve .SS "Adding periodically scheduled tasks" .IX Subsection "Adding periodically scheduled tasks" When mtpolicyd is called with the option \-\-cron it will execute all plugins that implement a \fIcron()\fR function. .PP The function is expected to take the following parameters: .PP .Vb 1 \& $plugin\->cron( $server, @tasks ); .Ve .PP By default mtpolicyd ships with a crontab that will execute the tasks hourly,daily,weekly and monthly. .PP A plugin that implements a weekly task may look like this: .PP .Vb 3 \& sub cron { \& my $self = shift; \& my $server = shift; \& \& if( grep { $_ eq \*(Aqweekly\*(Aq } @_ ) { \& # do some weekly tasks \& $server\->log(3, \*(Aqi am a weekly task\*(Aq); \& } \& } .Ve .PP The \f(CW$server\fR object could be used for logging. .PP To see the output on the commandline you may call mtpolicyd like this: .PP .Vb 1 \& mtpolicyd \-f \-l 4 \-\-cron=weekly .Ve .SH "AUTHOR" .IX Header "AUTHOR" Markus Benning .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is Copyright (c) 2014 by Markus Benning . .PP This is free software, licensed under: .PP .Vb 1 \& The GNU General Public License, Version 2, June 1991 .Ve