package Email::Send; use strict; use vars qw[$VERSION]; $VERSION = '2.192'; use Email::Simple; use Module::Pluggable search_path => 'Email::Send', except => $Email::Send::__plugin_exclusion; use Return::Value; use Scalar::Util (); =head1 NAME Email::Send - Simply Sending Email =head1 SYNOPSIS use Email::Send; my $message = <<'__MESSAGE__'; To: recipient@example.com From: sender@example.com Subject: Hello there folks How are you? Enjoy! __MESSAGE__ my $sender = Email::Send->new({mailer => 'SMTP'}); $sender->mailer_args([Host => 'smtp.example.com']); $sender->send($message); # more complex my $bulk = Email::Send->new; for ( qw[SMTP Sendmail Qmail] ) { $bulk->mailer($_) and last if $bulk->mailer_available($_); } $bulk->message_modifier(sub { my ($sender, $message, $to) = @_; $message->header_set(To => qq[$to\@geeknest.com]) }); my @to = qw[casey chastity evelina casey_jr marshall]; my $rv = $bulk->send($message, $_) for @to; =head1 DESCRIPTION This module provides a very simple, very clean, very specific interface to multiple Email mailers. The goal of this software is to be small and simple, easy to use, and easy to extend. =head2 Constructors =over 4 =item new my $sender = Email::Send->new({ mailer => 'NNTP', mailer_args => [ Host => 'nntp.example.com' ], }); Create a new mailer object. This method can take parameters for any of the data properties of this module. Those data properties, which have their own accessors, are listed under L<"Properties">. =back =head2 Properties =over 4 =item mailer The mailing system you'd like to use for sending messages with this object. This is not defined by default. If you don't specify a mailer, all available plugins will be tried when the C method is called until one succeeds. =item mailer_args Arguments passed into the mailing system you're using. =item message_modifier If defined, this callback is invoked every time the C method is called on an object. The mailer object will be passed as the first argument. Second, the actual C object for a message will be passed. Finally, any additional arguments passed to C will be passed to this method in the order they were recieved. This is useful if you are sending in bulk. =back =cut sub new { my ($class, $args) = @_; $args->{mailer_args} ||= []; my %plugins = map { my ($short_name) = /^Email::Send::(.+)/; ($short_name, $_); } $class->plugins; $args->{_plugin_list} = \%plugins; return bless $args => $class; } BEGIN { for my $field (qw(mailer mailer_args message_modifier _plugin_list)) { my $code = sub { return $_[0]->{$field} unless @_ > 1; my $self = shift; $self->{$field} = (@_ == 1 ? $_[0] : [@_]); }; no strict 'refs'; *$field = $code; } } =head2 METHODS =over 4 =item send my $result = $sender->send($message, @modifier_args); Send a message using the predetermined mailer and mailer arguments. If you have defined a C it will be called prior to sending. The first argument you pass to send is an email message. It must be in some format that C can understand. If you don't have C installed then sending as plain text or an C object will do. Any remaining arguments will be passed directly into your defined C. =cut sub send { goto &_send_function unless eval { $_[0]->isa('Email::Send') }; my ($self, $message, @args) = @_; my $simple = $self->_objectify_message($message); return failure "No message found." unless $simple; $self->message_modifier->( $self, $simple, @args, ) if $self->message_modifier; if ( $self->mailer ) { return $self->_send_it($self->mailer, $simple); } return $self->_try_all($simple); } =item all_mailers my @available = $sender->all_mailers; Returns a list of availabe mailers. These are mailers that are installed on your computer and register themselves as available. =cut sub all_mailers { my ($self) = @_; my @mailers; for ( keys %{$self->_plugin_list} ) { push @mailers, $_ if $self->mailer_available($_); } return @mailers; } =item mailer_available # is SMTP over SSL avaialble? $sender->mailer('SMTP') if $sender->mailer_available('SMTP', ssl => 1); Given the name of a mailer, such as C, determine if it is available. Any additional arguments passed to this method are passed directly to the C method of the mailer being queried. =back =cut sub mailer_available { my ($self, $mailer, @args) = @_; my $invocant = $self->_mailer_invocant($mailer); return $invocant unless $invocant; $invocant->can('is_available') or return failure "Mailer $mailer doesn't report availability."; my $test = $invocant->is_available(@args); return $test unless $test; return success; } sub _objectify_message { my ($self, $message) = @_; return undef unless defined $message; return $message if UNIVERSAL::isa($message, 'Email::Simple'); return Email::Simple->new($message) unless ref($message); return Email::Abstract->cast($message => 'Email::Simple') if eval { require Email::Abstract }; return undef; } sub _mailer_invocant { my ($self, $mailer) = @_; return $mailer if Scalar::Util::blessed($mailer); # is the mailer a plugin given by short name? my $package = exists $self->_plugin_list->{$mailer} ? $self->_plugin_list->{$mailer} : $mailer; eval "require $package" or return failure "$@"; return $package; } sub _send_it { my ($self, $mailer, $message) = @_; my $test = $self->mailer_available($mailer); return $test unless $test; my $invocant = $self->_mailer_invocant($mailer); return $invocant->send($message, @{$self->mailer_args}); } sub _try_all { my ($self, $simple) = @_; foreach ( $self->all_mailers ) { my $sent = $self->_send_it($_, $simple); return $sent if $sent; } return failure "Unable to send message."; } # Classic Interface. sub import { no strict 'refs'; *{(caller)[0] . '::send'} = __PACKAGE__->can('_send_function'); } sub _send_function { my ($mailer, $message, @args) = @_; __PACKAGE__->new({ mailer => $mailer, mailer_args => \@args, })->send($message); } 1; __END__ =head2 Writing Mailers package Email::Send::Example; sub is_available { eval { use Net::Example } } sub send { my ($class, $message, @args) = @_; use Net::Example; Net::Example->do_it($message) or return; } 1; Writing new mailers is very simple. If you want to use a short name when calling C, name your mailer under the C namespace. If you don't, the full name will have to be used. A mailer only needs to implement a single function, C. It will be called from C exactly like this. Your::Sending::Package->send($message, @args); C<$message> is an Email::Simple object, C<@args> are the extra arguments passed into C. Here's an example of a mailer that sends email to a URL. package Email::Send::HTTP::Post; use strict; use vars qw[$AGENT $URL $FIELD]; use Return::Value; sub is_available { eval { use LWP::UserAgent } } sub send { my ($class, $message, @args); require LWP::UserAgent; if ( @args ) { my ($URL, $FIELD) = @args; $AGENT = LWP::UserAgent->new; } return failure "Can't send to URL if no URL and field are named" unless $URL && $FIELD; $AGENT->post($URL => { $FIELD => $message->as_string }); return success; } 1; This example will keep a UserAgent singleton unless new arguments are passed to C. It is used by calling C. my $sender = Email::Send->new({ mailer => 'HTTP::Post' }); $sender->mailer_args([ 'http://example.com/incoming', 'message' ]); $sender->send($message); $sender->send($message2); # uses saved $URL and $FIELD =head1 SEE ALSO L, L, L, L, L, L, L, L. =head1 PERL EMAIL PROJECT This module is maintained by the Perl Email Project. L =head1 AUTHOR Current maintainer: Ricardo SIGNES, >. Original author: Casey West, >. =head1 COPYRIGHT Copyright (c) 2005 Casey West. All rights reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut