Footer.of_children (added in #10) emits:
<table border="0" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td>[children]</td>
</tr>
</table>
Every other structural component in typemail (Section, Callout, Spacer) adds width="100%" to its outer <table>. Without it, the footer table collapses to the content width in Outlook and right-aligns or left-aligns unpredictably depending on surrounding padding. The result is a misaligned footer block that doesn't sit flush with the rest of the email body.
Repro
let footer =
Footer.of_children
[Paragraph.to_element (Paragraph.v "Line 1");
Paragraph.to_element (Paragraph.v "Line 2")]
|> Footer.to_element
Rendered (whitespace-stripped):
<table border="0" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td>
<p>Line 1</p>
<p>Line 2</p>
</td>
</tr>
</table>
No width="100%". Compare to Section.v [...] which does include it. The string-content Footer.v path is probably the same (worth checking).
Fix
lib/footer.ml — add "width", "100%" to the base attribute list for both v and of_children rendering paths. Update the structure test to assert width="100%" on the footer's outer table, mirroring the Section test.
Filed during feedmansion.com#1024.
Footer.of_children(added in #10) emits:Every other structural component in typemail (
Section,Callout,Spacer) addswidth="100%"to its outer<table>. Without it, the footer table collapses to the content width in Outlook and right-aligns or left-aligns unpredictably depending on surrounding padding. The result is a misaligned footer block that doesn't sit flush with the rest of the email body.Repro
Rendered (whitespace-stripped):
No
width="100%". Compare toSection.v [...]which does include it. The string-contentFooter.vpath is probably the same (worth checking).Fix
lib/footer.ml— add"width", "100%"to the base attribute list for bothvandof_childrenrendering paths. Update the structure test to assertwidth="100%"on the footer's outer table, mirroring the Section test.Filed during feedmansion.com#1024.