Revision 740 (by ahitrov, 2018/11/12 22:03:41) in-core e-mail sender

package Contenido::Mail;

use Net::SMTP;
use MIME::Lite;
use MIME::Base64;
use Data::Dumper;
use Contenido::Globals;

sub new {
    my ($proto) = @_;
    my $class = ref($proto) || $proto;
    my $self = {};

    $self->{enable} = $state->{email_enable};
    if ( $self->{enable} ) {
	$self->{mailer} = $state->{email_mailer};
	$self->{from} = $state->{email_from};
	$self->{login} = $state->{email_auth_login};
	$self->{password} = $state->{email_auth_password};
	if ( $self->{mailer} eq 'smtp' ) {
		$self->{server} = $state->{email_smtp_server};
		$self->{hello} = $state->{email_smtp_hello};
		$self->{timeout} = $state->{email_smtp_timeout};
		$self->{ssl} = $state->{email_smtp_ssl};
		$self->{port} = $state->{email_smtp_port};
	}
    }

    bless $self, $class;
    return $self;
}

sub send {
    return	unless @_;
    my $self;
    if ( ref $_[0] eq 'Contenido::Mail' ) {
	$self = shift;
    } else {
	$self = Contenido::Mail->new;
    }

    my $opts = shift // {};

    my $email = delete $opts->{email} // return undef;
    return	unless ref $email && exists $email->{to} && $email->{subject} && $email->{body};

    my $etype = delete $opts->{etype} // 'mixed';
    my $debug = $state->development || $DEBUG || $opts->{debug} ? 1 : 0;

    my $subject = $email->{subject};
    $subject = MIME::Base64::encode($subject);
    $subject =~ s/\s//sgi;
    $subject = '=?utf-8?B?'.$subject.'?=';

    my $emailfrom;
    if ( $email->{from} ) {
	my ($from, $efrom) = $email->{from} =~ /^(.*?)<(.*?)>/ ? ($1, $2) : $email->{from} =~ /<(.*?)>/ ? ('',$1) : ('',$email->{from});
	if ( $from ) {
		$from = MIME::Base64::encode($from);
		$from =~ s/\s+$//si;
		$from = '=?utf-8?B?'.$from.'?=';
		$emailfrom = $from.' <'.$efrom.'>';
	} else {
		$emailfrom = $efrom;
	}
    } elsif ( $state->{email_from} ) {
	$emailfrom = $self->{from}
    }

    my ($emailto, @to);
    if ( ref $email->{to} eq 'ARRAY' ) {
	foreach my $tostr ( @{$email->{to}} ) {
		my ($to, $eto) = $tostr =~ /^(.*?)<(.*?)>/ ? ($1, $2) : $tostr =~ /<(.*?)>/ ? ('',$1) : ('',$tostr);
		if ( $to ) {
			$to = MIME::Base64::encode($to);
			$to =~ s/\s+$//si;
			$to = '=?utf-8?B?'.$to.'?=';
			push @to, $to.' <'.$eto.'>';
		} else {
			push @to, $eto;
		}
	}
	$emailto = shift @to;
    } else {
	my ($to, $eto) = $email->{to} =~ /^(.*?)<(.*?)>/ ? ($1, $2) : $email->{to} =~ /<(.*?)>/ ? ('',$1) : ('',$email->{to});
	if ( $to ) {
		$to = MIME::Base64::encode($to);
		$to =~ s/\s+$//si;
		$to = '=?utf-8?B?'.$to.'?=';
		$emailto = $to.' <'.$eto.'>';
	} else {
		$emailto = $eto;
	}
    }

    my $ccmail;
    if ( exists $email->{cc} && ref $email->{cc} eq 'ARRAY' ) {
	foreach my $cc ( @{ $email->{cc}} ) {
		my ($cce, $ecce) = $cc =~ /^(.*?)<(.*?)>/ ? ($1, $2) : $cc =~ /<(.*?)>/ ? ('',$1) : ('',$cc);
		$cc = $ecce;
	}
	$ccmail = join ', ', (@to, @{$email->{cc}});
    } elsif ( exists $email->{cc} && $email->{cc} ) {
	my ($cce, $ecce) = $email->{cc} =~ /^(.*?)<(.*?)>/ ? ($1, $2) : $email->{cc} =~ /<(.*?)>/ ? ('',$1) : ('',$email->{cc});
	$ccmail = join ', ', (@to, $ecce);
    } elsif ( @to ) {
	$ccmail = join ', ', @to;
    }

    my $body = $email->{body};
    warn Dumper($email)			if $debug;
    my $dt = Contenido::DateTime->new;
    $dt->set_locale('en_EN');
    my $pdate = $dt->strftime("%a, %d %b %Y %H:%M:%S %z");
    my $msg = MIME::Lite->new(
		To      => $emailto,
		From    => $emailfrom,
		$ccmail ? ( Cc => $ccmail ) : (),
		Subject => $subject,
#		Encoding=> 'binary',
		Date    => $pdate,
		Type    => ($etype eq 'mixed' ? 'multipart/mixed' : $etype eq 'related' ? 'multipart/related;type="multipart/alternative";charset="utf-8"' : $etype),
	);
    $msg->attach(
		'Type' => 'text/html;charset="utf-8"',
		'Data' => $body,
		'Disposition'   => '',
	);

    my $email_body = $msg->as_string;
    if ( $self->mailer eq 'smtp' ) {
	my $mailer = Net::SMTP->new( $self->{server},
			$self->{hello} ? (Hello => $self->{hello}) : (),
			Port    => $self->{port},
			Timeout => $self->{timeout},
			SSL     => $self->{ssl},
			Debug   => $debug,
		);
	warn Dumper $mailer			if $debug;
	if ( ref $mailer ) {
		if ( $self->{login} && $self->{password} ) {
			$mailer->auth( $self->{login}, $self->{password} );
		}
		$mailer->mail( $emailfrom );
		$mailer->to( $emailto );
		$mailer->data;
		$mailer->datasend( $email_body );
		$mailer->dataend;
		$mailer->quit;
	} else {
		warn "MAIL ERROR! Can't connect to Yandex SMTP\n";
	}
    }
}


1;