Revision 852 (by ahitrov, 2023/08/15 13:52:02) Some bugs
package Contenido::Mail;

use strict;
use warnings;

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

use parent 'Contenido::Accessor';
__PACKAGE__->mk_accessors(qw(enable mailer from login password server hello timeout ssl port));

use Contenido::Globals;
use Contenido::Email;

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

    $self->enable( $state->{email_enable} );
    if ( $self->enable ) {
	$self->mailer( $state->{email_mailer} );
	$self->from( $state->{email_from} );
	$self->login( delete $args->{login} || $state->{email_auth_login} );
	$self->password( delete $args->{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} );
	}
    }

    warn Dumper $self		if $DEBUG;
    return $self;
}

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

    my $opts = shift // {};
    my $debug = $state->development || $DEBUG || $opts->{debug} ? 1 : 0;

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

    my $etype = delete $opts->{etype} // 'mixed';

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

    my $error;
    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 ( $self->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 = join ', ',  @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;
	}
	push @to, $emailto;
    }

    my $ccmail;
    if ( exists $email->{cc} && ref $email->{cc} eq 'ARRAY' ) {
	my @cc;
	foreach my $cc ( @{ $email->{cc}} ) {
		my ($cce, $ecce) = $cc =~ /^(.*?)<(.*?)>/ ? ($1, $2) : $cc =~ /<(.*?)>/ ? ('',$1) : ('',$cc);
		if ( $cce ) {
			$cce = MIME::Base64::encode($cce);
			$cce =~ s/\s+$//si;
			$cce = '=?utf-8?B?'.$cce.'?=';
			push @to, $cce.' <'.$ecce.'>';
			push @cc, $cce.' <'.$ecce.'>';
		} else {
			push @to, '<'.$ecce.'>';
			push @cc, '<'.$ecce.'>';
		}
	}
	$ccmail = join ', ', @cc;
    } elsif ( exists $email->{cc} && $email->{cc} ) {
	my ($cce, $ecce) = $email->{cc} =~ /^(.*?)<(.*?)>/ ? ($1, $2) : $email->{cc} =~ /<(.*?)>/ ? ('',$1) : ('',$email->{cc});
	if ( $cce ) {
		$cce = MIME::Base64::encode($cce);
		$cce =~ s/\s+$//si;
		$cce = '=?utf-8?B?'.$cce.'?=';
		$ccmail = $cce.' <'.$ecce.'>';
	} else {
		$ccmail = $ecce;
	}
	push @to, $ccmail;
    }

    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} );
			unless ( $mailer->ok ) {
				$error = $mailer->message;
			}
		}
		unless ( $error ) {
			$mailer->mail( $emailfrom );
			unless ( $mailer->ok ) {
				$error = $mailer->message;
			}
		}
		unless ( $error ) {
			$mailer->to( @to );
			unless ( $mailer->ok ) {
				$error = $mailer->message;
			}
		}
		unless ( $error ) {
			$mailer->data;
			$mailer->datasend( $email_body );
			$mailer->dataend;
		}
		$mailer->quit;
	} else {
		$error = "MAIL ERROR! Can't create SMTP object";
		warn "$error\n";
	}
    }
    return $error;
}


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

    my $opts = shift // {};
    my $debug = $state->development || $DEBUG || $opts->{debug} ? 1 : 0;

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

    my $que = Contenido::Email->new( $keeper );
    $que->status( 0 );
    if ( ref $email->{to} eq 'ARRAY' ) {
	my @to = grep { $_ } @{$email->{to}};
	return	unless @to;
	$que->name( join ',', @to );
    } else {
	return	unless $email->{to};
	$que->name( $email->{to} );
    }
    if ( exists $email->{cc} && ref $email->{cc} eq 'ARRAY' ) {
	$que->cc( join("\n", @{$email->{cc}}) );
    } elsif ( exists $email->{cc} && $email->{cc} ) {
	$que->cc( $email->{cc} );
    }
    if ( exists $email->{from} && $email->{from} ) {
	$que->from( $email->{from} );
    }
    $que->subject( $email->{subject} );
    $que->body_html( $email->{body} );
    if ( exists $email->{text} ) {
	$que->body_text( $email->{text} );
    }
    if ( exists $email->{date} && ref $email->{date} eq 'DateTime' ) {
	$que->dtime( $email->{date}->ymd('-').' '.$email->{date}->hms );
    } elsif ( exists $email->{date} && $email->{date} ) {
	my $dt;
	eval{ $dt = Contenido::DateTime->new( postgres => $email->{date} ) };
	if ( ref $dt ) {
		$que->dtime( $dt->ymd('-').' '.$dt->hms );
	}
    } else {
	my $now = Contenido::DateTime->new;
	$que->dtime( $now->ymd('-').' '.$now->hms );
    }
    if ( $que->store ) {
	return $que;
    }
    warn "Store failed!!!!\n"		if $debug;
    return undef;
}

1;