lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm

256 lines
7.7 KiB
Perl
Raw Normal View History

##@file
# SMTP common functions
##@class
# SMTP common functions
2017-01-04 06:52:39 +01:00
package Lemonldap::NG::Portal::Lib::SMTP;
use strict;
2017-01-04 06:52:39 +01:00
use Mouse;
2017-02-17 21:47:01 +01:00
use JSON qw(from_json);
use MIME::Entity;
2017-03-26 07:26:28 +02:00
use Email::Sender::Simple qw(sendmail);
use Email::Date::Format qw(email_date);
use Lemonldap::NG::Common::EmailTransport;
2011-06-21 14:31:45 +02:00
use MIME::Base64;
2011-05-27 16:08:49 +02:00
use Encode;
2021-06-28 15:36:29 +02:00
our $VERSION = '2.0.12';
our $transport;
2017-01-04 06:52:39 +01:00
# PROPERTIES
2017-01-04 06:53:34 +01:00
has random => (
is => 'rw',
default => sub {
return Lemonldap::NG::Common::Crypto::srandom();
2017-01-04 06:53:34 +01:00
}
);
has charset => (
is => 'rw',
lazy => 1,
2017-01-04 06:53:34 +01:00
default => sub { return $_[0]->{conf}->{mailCharset} || 'utf-8' }
);
2017-03-26 07:26:28 +02:00
has transport => (
is => 'rw',
lazy => 1,
2017-03-26 07:26:28 +02:00
default => sub {
return $transport if $transport;
2017-03-26 07:26:28 +02:00
my $conf = $_[0]->{conf};
$transport = Lemonldap::NG::Common::EmailTransport->new($conf);
return $transport;
2017-03-26 07:26:28 +02:00
},
);
2017-01-04 06:52:39 +01:00
sub loadMailTemplate {
my ( $self, $req, $name, %prm ) = @_;
# HTML::Template cache interferes with email translation (#1897)
2022-02-16 17:43:29 +01:00
$prm{cache} = 0 unless defined $prm{cache};
$prm{params}->{STATIC_PREFIX} = $self->p->staticPrefix;
$prm{params}->{MAIN_LOGO} = $self->conf->{portalMainLogo};
my %extra =
$self->p->can('tplParams')
? $self->p->tplParams($req)
: ();
$prm{params}->{$_} = $extra{$_} for keys %extra;
return $self->loadTemplate( $req, $name, %prm );
}
2017-02-17 21:47:01 +01:00
sub translate {
my ( $self, $req ) = @_;
# Get language using llnglanguage cookie
my $lang_code = $req->cookies->{llnglanguage} || 'en';
2019-07-02 20:03:40 +02:00
my $json = $self->conf->{templateDir} . "/common/mail/$lang_code.json";
2017-02-17 21:47:01 +01:00
$json = $self->conf->{templateDir} . '/common/mail/en.json'
unless ( -f $json );
2019-08-28 11:32:29 +02:00
open F, '<', $json
2017-12-11 19:36:55 +01:00
or die 'Installation error: '
. $!
. " ($self->{conf}->{templateDir}/$lang_code.json or $self->{conf}->{templateDir}/common/mail/en.json)";
2017-02-17 21:47:01 +01:00
$json = join '', <F>;
close F;
my $lang = from_json( $json, { allow_nonref => 1 } );
my $langOver = from_json( $self->p->trOver, { allow_nonref => 1 } );
if ($langOver) {
for my $k ( keys %{ $langOver->{all} || {} } ) {
2019-08-02 17:45:03 +02:00
$lang->{$k} = $langOver->{all}->{$k};
}
for my $k ( keys %{ $langOver->{$lang_code} || {} } ) {
$lang->{$k} = $langOver->{$lang_code}->{$k};
}
}
2017-02-17 21:47:01 +01:00
return sub {
($_) = @_;
$$_ =~ s/\s+trspan="(\w+?)"(.*?)>.*?</"$2>".($lang->{$1}||$1).'<'/gse;
$$_ =~ s/^(\w+)$/$lang->{$1}||$1/es;
2017-02-17 21:47:01 +01:00
};
}
# Generate a complex password based on a regular expression
# @param regexp regular expression
sub gen_password {
2017-01-04 06:53:34 +01:00
my ( $self, $regexp ) = @_;
2017-01-04 06:52:39 +01:00
return $self->random->randregex($regexp);
}
# Send mail
# @param mail recipient address
# @param subject mail subject
# @param body mail body
# @param html optional set content type to HTML
# @return boolean result
sub send_mail {
my ( $self, $mail, $subject, $body, $html ) = @_;
$self->logger->info("send_mail called to send \"$subject\" to $mail");
2011-05-27 16:08:49 +02:00
# Encode the body with the given charset
$body = encode( $self->charset, decode( 'utf-8', $body ) );
$subject = encode( $self->charset, decode( 'utf-8', $subject ) );
2011-05-27 16:08:49 +02:00
# Debug messages
2017-02-15 07:41:50 +01:00
$self->logger->debug( "SMTP From " . $self->conf->{mailFrom} );
$self->logger->debug( "SMTP To " . $mail );
$self->logger->debug( "SMTP Subject " . $subject );
$self->logger->debug( "SMTP Body " . $body );
$self->logger->debug( "SMTP HTML flag " . ( $html ? "on" : "off" ) );
$self->logger->debug( "SMTP Reply-To " . $self->conf->{mailReplyTo} )
2017-01-14 20:31:48 +01:00
if $self->conf->{mailReplyTo};
2011-05-27 11:41:13 +02:00
2011-05-27 16:30:14 +02:00
# Encode the subject
2016-12-29 07:25:07 +01:00
$subject = encode_base64( $subject, '' );
2017-01-04 06:52:39 +01:00
$subject =~ s/\s//gs;
2017-01-04 06:53:34 +01:00
$subject = '=?' . $self->charset . "?B?$subject?=";
2011-05-27 16:30:14 +02:00
# Detect included images (cid)
my %cid = ( $body =~ m/"cid:([^:]+):([^"]+)"/g );
# Replace cid in body
$body =~ s/"cid:([^:]+):([^"]+)"/"cid:$1"/g;
eval {
# Create message
my $message;
# HTML case
if ($html) {
2017-03-26 07:26:28 +02:00
$message = MIME::Entity->build(
2017-01-14 20:31:48 +01:00
From => $self->conf->{mailFrom},
To => $mail,
(
$self->conf->{mailReplyTo}
? ( "Reply-To" => $self->conf->{mailReplyTo} )
: ()
),
Subject => $subject,
Type => 'multipart/related',
Date => email_date,
);
# Attach HTML message
$message->attach(
2017-01-04 06:53:34 +01:00
Type => 'text/html; charset=' . $self->charset,
Data => qq{$body},
);
# Attach included images
foreach ( keys %cid ) {
$message->attach(
Type => "image/" . ( $cid{$_} =~ m/\.(\w+)/ )[0],
2019-05-16 20:45:14 +02:00
Id => $_,
Path => $self->conf->{templateDir} . "/"
. $self->conf->{portalSkin} . "/"
. $cid{$_},
);
}
}
# Plain text case
else {
2017-03-26 07:26:28 +02:00
$message = MIME::Entity->build(
2017-01-14 20:31:48 +01:00
From => $self->conf->{mailFrom},
To => $mail,
2017-01-14 20:31:48 +01:00
"Reply-To" => $self->conf->{mailReplyTo},
Subject => $subject,
Type => 'TEXT',
Data => $body,
Type => 'text/plain',
Charset => $self->charset,
Date => email_date,
);
}
# Send the mail
sendmail( $message->stringify,
( $self->transport ? { transport => $self->transport } : () ) );
};
if ($@) {
2020-09-15 17:29:08 +02:00
$self->logger->error( "Send message failed: "
. ( $@->isa('Throwable::Error') ? $@->message : $@ ) );
return 0;
}
return 1;
}
## @method string getMailSession(string user)
# Check if a mail session exists
# @param user the value of the user key in session
# @return the first session id found or nothing if no session
sub getMailSession {
my ( $self, $user ) = @_;
2017-01-04 06:52:39 +01:00
my $moduleOptions = $self->conf->{globalStorageOptions} || {};
$moduleOptions->{backend} = $self->conf->{globalStorage};
my $module = "Lemonldap::NG::Common::Apache::Session";
# Search on mail sessions
my $sessions = $module->searchOn( $moduleOptions, "user", $user );
# Browse found sessions to check if it's a mail session
foreach my $id ( keys %$sessions ) {
my $mailSession =
$self->p->getApacheSession( $id, ( kind => "TOKEN" ) );
next unless ($mailSession);
2017-01-29 10:11:27 +01:00
return $mailSession if ( $mailSession->data->{_type} =~ /^mail$/ );
}
# No mail session found, return empty string
return "";
}
2014-05-23 20:47:36 +02:00
## @method string getRegisterSession(string mail)
# Check if a register session exists
# @param mail the value of the mail key in session
# @return the first session id found or nothing if no session
sub getRegisterSession {
my ( $self, $mail ) = @_;
2014-05-23 20:47:36 +02:00
2017-01-04 06:52:39 +01:00
my $moduleOptions = $self->conf->{globalStorageOptions} || {};
$moduleOptions->{backend} = $self->conf->{globalStorage};
2014-05-23 20:47:36 +02:00
my $module = "Lemonldap::NG::Common::Apache::Session";
# Search on register sessions
my $sessions = $module->searchOn( $moduleOptions, "mail", $mail );
# Browse found sessions to check if it's a register session
foreach my $id ( keys %$sessions ) {
my $registerSession =
$self->p->getApacheSession( $id, ( kind => "TOKEN" ) );
next unless ($registerSession);
2017-12-19 09:29:35 +01:00
return $id
if ( $registerSession->data->{_type}
and $registerSession->data->{_type} =~ /^register$/ );
2014-05-23 20:47:36 +02:00
}
# No register session found, return empty string
return "";
}
1;