Sure, maybe ChatGPT should have been specifically prompted with 'Outlook isn't rendering this HTML document correctly, tell me why'
... what did you ask it then? Yes you should always be as specific as possible about what you want the AI to help you diagnose. Especially be sure to mention any edge cases or design constraints you want it to think about. The AI is essentially the most learned person on earth giving you an off-the-cuff hot-take about what it knows about your problem without thinking too much about it, so the more topics you "jog its memory" about, the better the answer you get.
I've had quite good luck with ChatGPT, but only limited to small topical questions. I haven't gotten it to really write my code for me except for one time when I had it write a SMTP-receiving mini mail server in python. It seems to have more trouble with perl, presumably because there's so many ways to do things, the unusual context "gotchas", and perl's limited standard library.
I really wish there was a quick and easy way to share the prompts that resulted in successful outcomes, but my shares are limited to my company workspace, and copy/paste out of ChatGPT is mostly broken. Meanwhile, Claude 3.5 does a fair bit better than ChatGPT and I think we should probably switch to paying for that one instead.
Now, on the topic of email, if you want to get some nice looking HTML emails working in Outlook, especially old versions of outlook, here are my notes from the project where I do a bunch of that (using Template Toolkit in Email::MIME::Kit, though I recommend Email::MIME::CreateHTML instead):
[%#
Notes for email styles:
- Microsoft Outlook does not display "HTML Email", it imports the HTM
+L into a
Microsoft Word document and renders that. So, email styling is mor
+e about
what Microsoft Word is able to import than it is about correct HTML
+.
- never put "margin" on a table element, because some Outlook version
+s will
apply that to all of the table cells as well.
- Outlook can't properly handle padding on anything other than a tabl
+e cell
- Outlook can only have "border:collapse" on tables.
- never use "float" or absolute positioning
- you can't reliably create @print styles, so make everything work on
+ a 7.5" page
- Outlook can't do centered fixed-width content without using a table
+, so the
whole page needs wrapped in a table
- the "Mkit" system will inline all these styles into the elements th
+emselves,
because some email clients don't handle classes well.
%]
[%# Outlook has goofy spacing on list item elements. CSS flattens it
+down, but then unindent
to compensate for the default padding that we removed.
%]
<!--[if gte mso 9]>
<style>
li { text-indent: -1em; }
</style>
<![endif]-->
</head>
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" bg
+color='[% bgcolor %]'
style="margin: 0px; padding:0px; color:black; background-color:[% bg
+color %];">
[%# ----- PAGE WRAPPER ----- %]
[%# MS Office cant handle css width, so need to wrap everything with a
+ table %]
<!--[if mso]>
<table cellpadding="0" cellspacing="0" border="0" style="padding:0px;m
+argin:0px;width:100%;">
<tr>
<td style="padding:0px;margin:0px;"> </td>
<td style="padding:0px;margin:0px;width:800px;" width="800">
<font face="arial"><font face="calibri">
<![endif]-->
<div style='width:7.5in; margin:auto;
[% style_font_family %] font-size: 9pt;
color: black; background-color: [% bgcolor %];
'>
I've never had the problem you describe with blank lines. I would guess that either you've found a special misbehaving version of Outlook I've not encountered, or maybe your MIME structure or html declaration isn't correct. Here's one of ours:
From: example <example@example.com>
To: example <example@example.com>
Subject: Example
Date: Tue, 25 Mar 2025 13:02:21 -0500
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary=17429257410.7ADB6.10260
Content-Transfer-Encoding: 7bit
Message-ID: <17429257411.685ff8.10260@redacted.example.com>
--17429257410.7ADB6.10260
Date: Tue, 25 Mar 2025 13:02:21 -0500
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Example
--17429257410.7ADB6.10260
Date: Tue, 25 Mar 2025 13:02:21 -0500
MIME-Version: 1.0
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset=3D"UTF-8" />
<title>Example</title>
</head>
<body bgcolor=3D"#cccccc" leftmargin=3D"0" marginheight=3D"0" marginw
+idth=
=3D"0" offset=3D"0" topmargin=3D"0">
<table bgcolor=3D"#cccccc" cellpadding=3D"10" cellspacing=3D"0" widt
+h=3D"=
100%">
...
</table>
</body>
</html>
--17429257410.7ADB6.10260--
And an example of how to assemble that:
$text ||= HTML::FormatText::WithLinks->new(unique_links => 1)->pars
+e($html);
# Ugly workaround for WPEngine.com discriminating against perl
my $real_new= Email::MIME::CreateHTML::Resolver::LWP->can('new');
local *Email::MIME::CreateHTML::Resolver::LWP::new= sub {
my $self= $real_new->(@_);
$self->{UA}->agent(q{We're your customer, dammit, stop blocking
+perl});
$self->{UA}->protocols_allowed(['http', 'https']);
return $self;
};
# Build the email. The resolver will find all external images and
+stylesheets
# and suck them in as multiple parts.
my $viewable= Email::MIME->create_html(
header => [ ], # we use the unicode-enabled setters, instead
text_body_attributes => { charset => 'UTF-8', encoding => 'quote
+d-printable' },
text_body => encode('UTF-8', $text), # text gets assigned as-is
body_attributes => { charset => 'UTF-8', encoding => 'quoted-pri
+ntable' },
body => $html, # body gets assigned as body_str
embed => 1,
base => "https://redacted.example.com",
object_cache => $self->resource_cache, # Prevent excessive looku
+ps of resources
# Because most mail clients don't properly process <style> block
+s,
# we have to embed the style onto each individual element.
inline_css => 1,
%$args,
);
# Assemble MIME structure for attachments
my $email= @attachments?
Email::MIME->create(header => [], parts => [ $viewable, @attachm
+ents ])
: $viewable;
# These methods properly handle unicode, which is why we use them i
+nstead of
# passing these to the constructor
$email->header_str_set(To => (ref $to eq 'ARRAY'? join(', ',@$to) :
+ ''.$to));
$email->header_str_set(From => (ref $from eq 'ARRAY'? join(', ',@$f
+rom) : ''.$from));
$email->header_str_set(Subject => ''.$subject);
return $email;
}
|