Freemarker Loop to write tables - email

This is for email coding.
Seems simple in my head, but I have assigned a set of data to a freemarker variable
[#assign LOOP_TAB]${list.creative!'000000'}[/#assign]
Where list.creative contains either 1-5
I then want to write the correspsonding amount of simple HTML tables to my template
<!--Begin TEXT BOX-->
[#list 0..LOOP_TAB?length-1 as i]
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td align="left" valign="top" style="font-size: 14px; font-family: Arial, Helvetica, sans-serif; line-height: 20px; color: #000000;"><br>Loop Table Structure.<br><br></td>
</tr>
</tbody>
</table>[/#list]
Its sort of working, but im getting two tables by default, and never teh right amount of tables when i test on 2, or 4, or 1

Let me rename LOOP_TAB to numberOfTabs. So, if that's a number, and not a string, then:
[#list 1 ..< numberOfTabs!0 as _]
<table width="100%" border="0" cellspacing="0" cellpadding="0">
...
</table>
[/#list]
If numberOfTabs is a string, and you can't fix the data-model, then use (numberOfTabs?number)!0 instead of numberOfTabs!0.
Some further notes:
[#assign LOOP_TAB]${list.creative!'000000'}[/#assign] can be simply written as [#assign LOOP_TAB = list.creative!'000000']. But you don't need this at all, as you have seen.
?length gives the length of the strings in characters, so, it has returned the length of the string in LOOP_TABS.
from .. to gives an inclusive range, furthermore 0 .. -1 will give [0, -1], instead of the empty sequence that you wanted. Therefore you need from ..< to, which has exclusive end.
I used _ as loop variable only to signify that you don't actually read it anywhere. It's not special otherwise.

Related

Powershell email sender with html body (htmlbody.Replace)

I'm currently a C# dotnet automation engineer. One of my tests results output is via email. My tests results output goes through powershell. I'm fairly new to email templates and HTML in general.
It's a simple HTML body with variables that I replace with $EmailBody= $EmailBody.Replace("PassedTests",$Passed) function etc
The whole premise: my script replaces Total tests/Passed/Failed/Skipped with data that I extract from a .trx file after the test run.
My extraction code:
$PassedTests = $testResultsXml.TestRun.ResultSummary.Counters.Passed
$FailedTests = $testResultsXml.TestRun.ResultSummary.Counters.Failed
$SkippedTests = $testResultsXml.TestRun.ResultSummary.Counters.Skipped
$OnlyFailed = $testResultsXml.TestRun.Results.UnitTestResult | Where-Object { $_.outcome -eq "Failed" }
$FailedTestsName = $OnlyFailed.TestName
I have the "Error list" table (picture below) that shows test names if there are any failed tests that in the HTML body
#</td>
</tr>
<!--end img-->
<tr>
<td height="15"></td>
</tr>
<!--title-->
<tr align="center">
<td align="center" style="font-family:
'Open Sans', Arial, sans-serif; font-size:16px;color:#3b3b3b;font-weight: bold;">**ERROR LIST**</td>
</tr>
<!--end title-->
<tr>
<td height="10"></td>
</tr>
<!--content-->
<tr align="center">
<td align="center" style="font-family: 'Open Sans', Arial, sans-serif; font-size:12px;color:#7f8c8d;line-height: 24px;">NoErrors</td>
</tr>
<!--end content-->
</table>
</td>
</tr>
<tr>
<td height="30"></td>
</tr>
</table>
Now the main question is: is it somehow possible to ONLY show the "Error list" table only IF there are any failed tests? If there are no failed tests it would be great for that table not to be shown at all.
Any kind of help would be greatly appreciated. Thanks!
$EmailBody= $EmailBody.Replace("PassedTests",$Passed)
$EmailBody= $EmailBody.Replace("FailedTests",$Failed)
$EmailBody= $EmailBody.Replace("SkippedTests",$Skipped)
$EmailBody= $EmailBody.Replace("ErrorList",$FailedTestsName)
$Emailattachment = "\TestResults.trx"
You are on the good path.
You just need to extend what you are doing.
Remove the thing that might or might not be in the email (The "errors list" section as it won't be there if there are no error)
Put the section your removed in its own variable
Add a placeholder in your main html template at the location where it is supposed to be (just like you do already so we can do a replace in the html template.
From there, the logic is :
If there are 0 errors, you replace the placeholder from the main template by an empty string (you don't want that placeholder to appear in the final email)
If there are 1 or more error, instead of replacing by your error list, you build a new variable that contain the section you want to append, then you replace its loop by the errors content and finally you replace the placeholder by that section (which contains the error loop)
That would look something like this.
$EmailBody = #'
</td>
</tr>
<!--end img-->
<tr>
<td height="15"></td>
</tr>
**ErrorsTable**
'#
$ErrorListBody = #'
<!--title-->
<tr align="center">
<td align="center" style="font-family:
'Open Sans', Arial, sans-serif; font-size:16px;color:#3b3b3b;font-weight: bold;">**ERROR LIST**</td>
</tr>
<!--end title-->
<tr>
<td height="10"></td>
</tr>
<!--content-->
<tr align="center">
<td align="center" style="font-family: 'Open Sans', Arial, sans-serif; font-size:12px;color:#7f8c8d;line-height: 24px;">NoErrors</td>
</tr>
<!--end content-->
</table>
</td>
</tr>
<tr>
<td height="30"></td>
</tr>
</table>
'#
if ($FailedTests.Count -gt 0) {
# inserting errors to the `$ErrorListBody` html segment
$ErrorsHtml = $ErrorListBody.Replace("ErrorList", $FailedTestsName)
# inserting the html segment into the main email
$EmailBody = $EmailBody.Replace("**ErrorsTable**", $ErrorsHtml)
} else {
# Removing the placeholder from the main template.
$EmailBody = $EmailBody.Replace("**ErrorsTable**", '')
}

Html email and fluid table with changing borders

I have some design requirements for an email template where I have two "challenges":
two columns need to flip to one column
some visible border lines need to be switched from vertical to horizontal
The following shows how it should look (2 columns on the left for desktop, 1 column on the right for mobile):
The whole email is based on responsive tables and the two-column part is implemented as follows right now:
<table cellpadding="5" cellspacing="0"
style="background-color:#F6F6F6; font-size: 14px; color:#58595b; width:100%; border-collapse:collapse;">
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
<tr>
<td valign="top" style="border-right: 1.5px solid; border-color: #d0d0d0; padding-right:40px; text-align:right; width:42%; vertical-align:top;">
Start point
</td>
<td valign="top" style="padding-left:40px; vertical-align:top;">
<strong>Fri, January 12, 2023 12:00</strong>
<br />
Harbour, Seatown
</td>
</tr>
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
<tr>
<td valign="top" style="border-right: 1.5px solid; border-color: #d0d0d0; padding-right:40px; text-align:right; width:42%; vertical-align:top;">
End point
</td>
<td valign="top" style="padding-left:40px; vertical-align:top;">
<strong>So, January 18, 2023 10:00</strong>
<br />
Central Station, Capital
</td>
</tr>
<tr><td align="center" valign="top" height="10" colspan=2 style="line-height: 10px; font-size: 10px;"> </td></tr>
</table>
I tried the approach with having a left and a right table (explained here) but the problem is that I do not use fixed widths.
How could I achieve the required design with a responsive mail template?
You will need to use the technique as outlined in the link, but if you want to use percentages instead of fixed widths, then use width="50%".
This is because the technique works on the basic fundamentals of HTML, that if a block doesn't fit in the space available, it will automatically shift underneath.
So to enable the stacking without a fixed pixel width, you will need to add a #media query to force the stacking (otherwise it would not stack).
e.g.
#media (max-width: 620px)
.table-left,.table-right {
width: 100% !important;
}
(The article you link to is a bit outdated: don't use [class=...], just write it out normally. Gmail may strip the entire <style> section if it doesn't like something in it, and this is one of those things it doesn't like.)
I prefer an override (max-width, and !important) because you want everything possible inline, and only to use embedded styles where strictly necessary.
But that's also why it's best to use a fixed pixel width, because some email clients do not respect your embedded styles (styles in the <head>). GANGA emails (one form of Gmail account) fall into this category. Those email clients would not stack even though they may need to, if you fully rely on the #media query for the stacking.
To override the border, put a style on the <td>, and reference it in the #media query, e.g.
#media (max-width: 620px)
.border {
border-right:none!important;
}
.border-top {
border-bottom:1.5px solid #d0d0d0 !important;
}
As one doesn't have the same border structure (they don't both need border-bottom), one of the <td>s will need a different class. Here, I'm expecting the first one, i.e. <td class="border border-top">.

grouping tr but browser closes tbody prematurely

When using LitElement to render data dynamically, the browser inserts tbody all the time negating any effort to "group" table rows.
render() {
return html`
<table style="border-collapse:collapse;border:solid 1px #666;">
${this.rows.map((row)=>{
var disp= html`
${(row=="FOUR")?html`</tbody>`:''}
${(row=="TWO")?html`
<tbody style="border:solid 2px #F00; border-collapse:separate;">
<tr>
<td>SOME HEADER</td>
</tr>
`:''}
<tr>
<td>${row}</td>
</tr>
`
return disp;
})}
</table>
`;
} //render()
constructor() {
super();
this.rows = ['ONE','TWO','THREE','FOUR'];
}
The result is the tbody is closed immediately after the closing tr of "SOME HEADER" instead of the tbody being closed after the tr "FOUR" which is what we want in this case.
It looks like the browser does this by itself because it always wants to insert a tbody whenever a tr is written to the DOM?
So I suspect this would happen to any framework that renders data dynamically - but have not verified this.
I assume this is not going to be "fixed" anytime soon.
That being the case, anyone have a suggestion on how to group tr's together in a block in this case?
Thanks!
If you have an unclosed <tbody> in a document fragment the browser will close it for you.
Instead nest the <tr> you want to group inside a template that holds both the <tbody> and closing </tbody>:
const groups = //process this.rows into groups
return html`
<table style="border-collapse:collapse;border:solid 1px #666;">
${groups.map(g => html`
<tbody style="border:solid 2px #F00; border-collapse:separate;">
<tr><th>${g.name}</th></tr>
${g.rows.map(r => html`
<tr><td>${r}</td></tr>`)}
</tbody>`)}
</table>`;

How can I add a dotted line between two texts with HTML2PDF

I'm trying to create a pricing recap at the end of a document I'm working on. I would like it to have a dotted line between the item on the left and the price on its right, very much like this :
However, this Index is generated with the createIndex function and I don't have the source HTML for this. And I've been trying since yesterday with differente HTML syntaxes to make it work but it is impossible. My best attempt so far is this one, but I can't automatically set the width of the dotted line :
<table style="width:100%;border-collapse: collapse;">
<tr>
<td style="width:40%;white-space:nowrap;">Item 1</td>
<td style="border-bottom:dotted 1px black;width:45%;"></td>
<td style="text-align:right;width:15%;white-space:nowrap;">Price 1€ HT</td>
</tr>
</table>
I really am stuck here, any advice would be welcome.
In this case you can use a little 'hack'. Unset the width of both texts (resolves to width: auto;) and set the width of the dotted line container to width: 99%;. For this to work you also need to set white-space: nowrap on the text elements, but you already did that.
<table style="width:100%;border-collapse: collapse;">
<tr>
<td style="white-space:nowrap;">Item 1</td>
<td style="border-bottom:dotted 1px black;width:99%"></td>
<td style="text-align:right;white-space:nowrap;">Price 1€ HT</td>
</tr>
</table>

Issue with image in table using GMail online client

I am creating an email template to use in Pardot. I have coded the email up. It works fine in OSX Mail, Outlook 07 +, Opera Mail, however GMail is being a real pain. It is adding some weird height or something to the tr or td in my table.
Any suggestions?
<table border="0" cellpadding="0" cellspacing="0" width="228">
<tbody>
<tr valign="bottom">
<td valign="bottom"><span pardot-region=""><img src="widget_top.jpg" alt="Placeholder"></span></td>
</tr>
<tr bgcolor="#ffd13f">
<td style="padding: 10px;">
<h2><span pardot-region="">Subheading span across one or two lines for best practice:</span></h2>
<span pardot-region=""><p><b>Date:</b> Thursday 29 November</p>
<p><b>Time:</b> 1.30pm (GMT)</p>
<p><b>Where:</b> Register online ></p>
<p><b>Topic:</b> Dynamic performance management</p>
<p><b>Presenters:</b> Octavius Black, CEO and Sebastian Bailey, President</p></span>
</td>
</tr>
<tr valign="top">
<td valign="top"><span pardot-region=""><img src="widget_bottom.jpg" alt="Placeholder"></span></td>
</tr>
</tbody>
</table>
(this table is inside a set of tested tables).
Screen shot can be found here: http://i45.tinypic.com/15wzda9.png
Cheers :)
On the images you have to put (inline)
style="display:block;"
:)
display:block; is definitely needed. You probably should zero out everything in all img tags, and set width and heights also.
<img style="margin: 0; border: 0; padding: 0; display: block;" src="" width="600" height="150"
alt="">
Also, you don't need the spans inside the table cells. If you want to keep them, make sure they have margin and padding zero'd out there too.