Skip to content

Commit fa580e6

Browse files
committed
Abstract inline CSS feature
CSS::Inliner is reused across the codebase. This abstraction eliminates duplication and simplifies future customization. Previously, the 1MB size limit was hard-coded. This commit replaces it with a package variable to make it configurable. Also update RT_Config doc as CSS::Inliner is now a core dependency.
1 parent ebfd792 commit fa580e6

File tree

5 files changed

+54
-37
lines changed

5 files changed

+54
-37
lines changed

etc/RT_Config.pm.in

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -974,12 +974,12 @@ formatting look very much like the corresponding RT page, but it also
974974
makes the emails very large. They can be large enough that some email
975975
servers will trim content because of the size.
976976

977-
To reduce the size of the emails, you can install the optional module
978-
C<CSS::Inliner> and enable the C<$EmailDashboardInlineCSS> option. When
979-
enabled, styles will be applied directly to the HTML in the email and
980-
the large C<style> sections are removed. This significantly reduces
981-
the size of dashboard emails at the cost of some detail in the styling.
982-
With this enabled, some parts of the email won't look exactly like RT.
977+
To reduce the size of the emails, you can enable the
978+
C<$EmailDashboardInlineCSS> option. When enabled, styles will be applied
979+
directly to the HTML in the email and the large C<style> sections are
980+
removed. This significantly reduces the size of dashboard emails at the
981+
cost of some detail in the styling. With this enabled, some parts of the
982+
email won't look exactly like RT.
983983

984984
=cut
985985

lib/RT/Dashboard/Mailer.pm

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ use File::Temp 'tempdir';
6262
use HTML::Scrubber;
6363
use URI::QueryParam;
6464
use List::MoreUtils qw( any none uniq );
65+
use RT::Util 'InlineCSS';
6566

6667
sub MailDashboards {
6768
my $self = shift;
@@ -613,21 +614,11 @@ sub BuildEmail {
613614
inline_imports => 1,
614615
);
615616

616-
# Inline the CSS if CSS::Inliner is installed and can be loaded
617+
# Inline the CSS
617618
if ( RT->Config->Get('EmailDashboardInlineCSS') ) {
618-
if ( RT::StaticUtil::RequireModule('CSS::Inliner') ) {
619-
# HTML::Query generates a ton of warnings about unsupported
620-
# pseudoclasses. Suppress those since they don't help the person
621-
# running RT.
622-
local $SIG{__WARN__} = sub {};
623-
624-
my $inliner = CSS::Inliner->new( { encode_entities => 1, ignore_style_type_attr => 1 } );
625-
$inliner->read({ html => $content });
626-
$content = $inliner->inlinify();
627-
}
628-
else {
629-
RT->Logger->warn('EmailDashboardInlineCSS is enabled but CSS::Inliner is not installed. Install the optional module CSS::Inliner to use this feature.');
630-
}
619+
# Mailer usually works at backend, remove the size limit
620+
local $RT::Util::INLINE_CSS_MAX_SIZE;
621+
$content = InlineCSS($content);
631622
}
632623

633624
my $entity = MIME::Entity->build(

lib/RT/Interface/Web/Scrubber.pm

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use 5.010;
5353
use base qw/HTML::Scrubber/;
5454

5555
use HTML::Gumbo;
56+
use RT::Util 'InlineCSS';
5657

5758
=head1 NAME
5859
@@ -247,14 +248,7 @@ sub scrub {
247248
warn "HTML::Gumbo pre-parse failed: $@" if $@;
248249
}
249250

250-
if ( ( length($Content) < ( 1024 * 1024 ) ) && $Content =~ /<style.*>/ ) {
251-
require CSS::Inliner;
252-
my $css_inliner = CSS::Inliner->new( { encode_entities => 1, ignore_style_type_attr => 1, ignore_selectors => ['pre'] } );
253-
$css_inliner->read( { html => $Content } );
254-
$Content = $css_inliner->inlinify();
255-
}
256-
257-
return $self->SUPER::scrub($Content);
251+
return $self->SUPER::scrub( InlineCSS($Content) );
258252
}
259253

260254
RT::Base->_ImportOverlays();

lib/RT/Transaction.pm

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ use vars qw( %_BriefDescriptions $PreferredContentType );
8181
use RT::Attachments;
8282
use RT::Scrips;
8383
use RT::Ruleset;
84+
use RT::Util 'InlineCSS';
8485

8586
use HTML::FormatText::WithLinks::AndTables;
8687
use HTML::Scrubber;
@@ -379,13 +380,6 @@ sub Content {
379380
if ($args{Type} ne 'text/html') {
380381
$content = RT::Interface::Email::ConvertHTMLToText($content);
381382
} else {
382-
if ( ( length($content) < ( 1024 * 1024 ) ) && $content =~ /<style.*>/ ) {
383-
require CSS::Inliner;
384-
my $css_inliner = CSS::Inliner->new( { encode_entities => 1, ignore_style_type_attr => 1, ignore_selectors => ['pre'] } );
385-
$css_inliner->read( { html => $content } );
386-
$content = $css_inliner->inlinify();
387-
}
388-
389383
# Scrub out <html>, <head>, <meta>, and <body>, and
390384
# leave all else untouched.
391385
my $scrubber = HTML::Scrubber->new();
@@ -396,7 +390,7 @@ sub Content {
396390
body => 0,
397391
);
398392
$scrubber->default( 1 => { '*' => 1 } );
399-
$content = $scrubber->scrub( $content );
393+
$content = $scrubber->scrub( InlineCSS($content) );
400394
}
401395
}
402396
else {

lib/RT/Util.pm

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use warnings;
5252

5353

5454
use base 'Exporter';
55-
our @EXPORT = qw/safe_run_child mime_recommended_filename EntityLooksLikeEmailMessage EmailContentTypes/;
55+
our @EXPORT = qw/safe_run_child mime_recommended_filename EntityLooksLikeEmailMessage EmailContentTypes InlineCSS/;
5656

5757
use Scalar::Util qw/weaken/;
5858
use Encode qw/encode/;
@@ -287,6 +287,44 @@ sub RecursiveSub {
287287
return $sub;
288288
}
289289

290+
=head2 InlineCSS CONTENT
291+
292+
For html CONTENT, convert CSS <style> blocks to inline styles.
293+
294+
=cut
295+
296+
our $INLINE_CSS_MAX_SIZE = 1024 * 1024;
297+
298+
sub InlineCSS {
299+
my $content = shift // return;
300+
301+
if ( $INLINE_CSS_MAX_SIZE && length($content) > $INLINE_CSS_MAX_SIZE ) {
302+
RT->Logger->debug("Content exceeds max size ($INLINE_CSS_MAX_SIZE), skipping");
303+
return $content;
304+
}
305+
306+
if ( $content !~ /<style.*>/ ) {
307+
RT->Logger->debug("Content does not contain style blocks, skipping");
308+
return $content;
309+
}
310+
311+
# HTML::Query generates a ton of warnings about unsupported
312+
# pseudoclasses. Suppress those since they don't help the person
313+
# running RT.
314+
local $SIG{__WARN__} = sub {};
315+
require CSS::Inliner;
316+
my $css_inliner = CSS::Inliner->new(
317+
{ encode_entities => 1,
318+
ignore_style_type_attr => 1,
319+
ignore_selectors => ['pre'],
320+
@_,
321+
}
322+
);
323+
$css_inliner->read( { html => $content } );
324+
return $css_inliner->inlinify();
325+
}
326+
327+
290328
require RT::Base;
291329
RT::Base->_ImportOverlays();
292330

0 commit comments

Comments
 (0)