use CSS::Inliner to inline styles where possible
authorTony Cook <tony@develop-help.com>
Fri, 13 May 2011 11:57:17 +0000 (21:57 +1000)
committerTony Cook <tony@develop-help.com>
Fri, 13 May 2011 11:57:17 +0000 (21:57 +1000)
INSTALL.pod
site/cgi-bin/admin/bse_modules.pl
site/cgi-bin/modules/BSE/ComposeMail.pm
site/docs/config.pod

index 9587b8f..ad98868 100644 (file)
@@ -140,6 +140,11 @@ Net::Amazon::S3 - for maintaining content on the Amazon S3 CDN.
 
 Captcha::reCAPTCHA - for displaying CAPTCHA's from Google reCAPTCHA.
 
+=item *
+
+CSS::Inliner - this is strongly desirable if you need the system to
+send email to the general public.
+
 =back
 
 =head1 PLANNING
index 4c7f32e..26cb675 100755 (executable)
@@ -70,6 +70,7 @@ my @base_check =
      'Captcha::reCAPTCHA' => 0,
      'FLV::Info' => 0,
      'DBM::Deep' => 2,
+     'CSS::Inliner' => 3042,
     },
    },
    {
index df36ea3..f15b8df 100644 (file)
@@ -5,7 +5,7 @@ use BSE::Mail;
 use Carp 'confess';
 use Digest::MD5 qw(md5_hex);
 
-our $VERSION = "1.001";
+our $VERSION = "1.002";
 
 =head1 NAME
 
@@ -116,7 +116,11 @@ sub start {
   $self->{attachments} = [];
   $self->{encrypt} = 0;
 
-  $self->{log} = {};
+  $self->{log} =
+    {
+     actor => "S",
+     component => "composemail::send",
+    };
   for my $key (keys %opts) {
     if ($key =~ /^log_(\w+)$/) {
       $self->{log}{$1} = $opts{$key};
@@ -428,6 +432,44 @@ sub done {
   else {
     my $html_content = BSE::Template->
       get_page($self->{html_template}, $self->{cfg}, \%acts);
+
+    my $inline_css = $self->{cfg}->entry("mail", "inline_css", "style");
+    if (($inline_css eq "style" && $html_content =~ /<style/i)
+       || $inline_css eq "force") {
+      my $report_failure = $self->{cfg}->entry("mail", "inline_css_report", 1);
+      my $good = eval {
+       require CSS::Inliner;
+       my $inliner = CSS::Inliner->new;
+       local $SIG{__DIE__};
+       $inliner->read({html => $html_content});
+       $html_content = $inliner->inlinify;
+       1;
+      };
+      if (!$good && $report_failure) {
+       my $error = $@;
+       require BSE::TB::AuditLog;
+       my %log = %{$self->{log}};
+       my $dump = <<DUMP;
+HTML:
+======
+$html_content
+======
+Error:
+======
+$error
+======
+DUMP
+       BSE::TB::AuditLog->log
+           (
+            %log,
+            msg => "Error inlining CSS",
+            component => "composemail:done:inlinecss",
+            level => "error",
+            dump => $dump,
+           );
+      }
+    }
+
     $message = $self->_build_mime_lite($content, $html_content, \@headers);
   }
   push @headers, $self->extra_headers;
@@ -443,7 +485,7 @@ sub done {
     if ($self->{cfg}->entry("audit log", "mail", 0)) {
       my %log_opts = %{$self->{log}};
       $log_opts{msg} ||= "Mail sent to $self->{to}";
-      $log_opts{component} ||= "composemail::send";
+      $log_opts{component} ||= "composemail:done:send";
       $log_opts{level} ||= "info";
       $log_opts{actor} ||= "S";
       $log_opts{dump} =$self->_log_dump($headers, $message);
@@ -455,7 +497,7 @@ sub done {
   else {
     my %log_opts = %{$self->{log}};
     $log_opts{msg} = "Error sending email: " . $mailer->errstr;
-    $log_opts{component} ||= "composemail:send";
+    $log_opts{component} ||= "composemail:done:send";
     $log_opts{level} ||= "error";
     $log_opts{actor} ||= "S";
     $log_opts{dump} = $self->_log_dump($headers, $message);
index b7148b7..e3e7466 100644 (file)
@@ -445,6 +445,22 @@ If non-zero then emails sent via the compose mail system that aren't
 being sent to a member record, will be sent as HTML, if the HTML
 template is available.
 
+=item inline_css
+
+If this is C<style> (the default) then use CSS::Inliner to attempt to
+inline CSS in mail if the text "<style" is found in the generated
+HTML.
+
+If this is C<force> then we always attempt to inline CSS.
+
+If this is any other value then don't inline CSS.
+
+=item inline_css_report
+
+If this is true and CSS inlining fails, log an error to the audit
+log. This is intended for use in debugging and should be disabled in
+production.  Default: false (disabled)
+
 =back
 
 =head2 [children of I<id>]