#!/usr/bin/perl use strict; use warnings; =pod =head1 DESCRIPTION Sends my mail to the ISP's mail server, using a TMDA dated return address. Maintains TMDA whitelist. Prints any warnings (!!) to standard out, not standard error, per system/libexec/mail-send-and-log. =cut use Email::Address (); use Email::Send (); use Email::Simple (); use File::stat (); use Zelea::SMTP (); print "mail-send...\n"; # Read message text from standard input. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - my $message = Email::Simple->new( join '', ); # Update TMDA whitelist with destination addresses, so they won't be challenged on reply. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - my $was_recipient_added_to_whitelist; { my $whitelist_file = '/home/mike/.tmda/white.address'; my $whitelist_file_modtime = File::stat::stat($whitelist_file)->mtime; my @destination_address = (); for my $destination_header_name( 'To', 'Cc', 'Bcc' ) { my $header = $message->header( $destination_header_name ); # always max 1 of each destination header for my $destination( Email::Address->parse( $header )) { my $address = $destination->address; push @destination_address, $address; } } # scalar @destination_address or last; ## regardless, sync the whitelist on mail.zelea.com, because it may have been offline during the last sync my $command = '/home/mike/system/bin/whitelist ' . join( ' ', @destination_address ); system $command and print ' !! warning, unable to execute: ' . $command; $was_recipient_added_to_whitelist = File::stat::stat($whitelist_file)->mtime != $whitelist_file_modtime; } # Set return-path and reply-to headers. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # When sending from a TMDA challenged address, # use a date-tagged return-path that goes unchallenged for a period of time. # Otherwise, if my message were to bounce back, TMDA would drop it (or challenge it, except that a bounce itself has no return address to bounce a challenge to) # and I would not learn about undeliverables, etc. # (I could use one of my rbs.rogers.com addresses for this, but they would soon get spammed.) # # And use a date-tagged reply-to too, when sending to a new (previously un-whitelisted) # recipient. There's no telling what address the recipient will reply from; # it might not be the one I'm sending to (and whitelisting). # See also the reply bypass in my incoming filter (grep 'Reply-To' there). # my $from_address = (Email::Address->parse($message->header('From')))[0]->address; my $return_path; my $reply_to; { my @reply_to_header = $message->header( 'Reply-To' ); if( scalar @reply_to_header && $reply_to_header[0] ) # already set manually by me, or automatically by mutt in some cases { $reply_to = (Email::Address->parse(@reply_to_header))[0]->address; } } if( $from_address =~ m'^mike(?:-.*)?@zelea\.com$' ) # this pattern will also cover a few unchallenged addresses, that may vary over time, but no harm { $return_path = `/usr/bin/tmda-address --address $from_address --dated 10d --no-newline`; if( $was_recipient_added_to_whitelist ) { if( !defined $reply_to ) { $reply_to = `/usr/bin/tmda-address --address $from_address --dated 5d --no-newline`; # $reply_to = $return_path; $message->header_set( 'Reply-To', $reply_to ); } } } else { $return_path = $from_address; } # Send the message. # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - print " sending From $from_address, Return-Path (envelope sender) $return_path"; defined $reply_to and print ", Reply-To $reply_to"; print "\n"; my $result = Email::Send::send ( # 'Zelea::SMTP', $message, 'smtp.rbs.rogers.com', Hello => "$ENV{HOSTNAME}.zelea.com", ### $ENV{HOSTNAME} undefined in latest system build, even though defined in environment 'Zelea::SMTP', $message, 'smtp.rbs.rogers.com', Hello => 'obsidian.zelea.com', ReturnPath => $return_path ); if( $result ) { my @bad = @{ $result->prop('bad') }; scalar @bad and print ' !! warning, could not send to: ' . join( ', ', @bad ) . "\n"; # cannot use warn, per POD DESCRIPTION } else { die $result . "\n"; } exit; __END__ =pod =head1 AUTHOR Michael Allan =cut