Add HTML email generator

This commit is contained in:
Pascal Le Merrer 2025-12-26 22:25:22 +01:00
parent 35b999c8c6
commit f1864d8841
14 changed files with 1748 additions and 16 deletions

View file

@ -0,0 +1,55 @@
# Email Generator Configuration
# Copy this file to config.yml and fill in your values
# Sendy API Configuration
sendy:
api_url: 'https://your-domain.com/api/campaigns/create.php'
api_key: 'your-api-key-here'
brand_id: '1'
list_ids: 'your-list-id-here'
# Email Settings
email:
from_name: 'Your Name'
from_email: 'your-email@example.com'
reply_to: 'your-email@example.com'
# Campaign Settings
campaign:
track_opens: '1'
track_clicks: '1'
default_timezone: 'America/Chicago'
# Template Settings
template:
header_image_url: 'https://your-domain.com/img/email/header.jpg'
header_image_alt: 'Email Header'
header_image_width: 600
header_image_height: 185
signature_image_url: 'https://your-domain.com/img/signature.png'
signature_image_alt: 'Signature'
signature_image_width: 98
signature_image_height: 98
signature_text: '-Your Name'
# Optional: Primary footer appears after signature, before unsubscribe section
# Can contain Markdown or HTML (e.g., product links, promotional content)
# primary_footer: |
# [![](/mas.jpg)](example.com "Purchase on the Mac App Store") | [![](/paddle.jpg)](example.com "Purchase directly")
# Footer text - can contain Markdown and will preserve <webversion> and <unsubscribe> tags
# Sendy will replace these tags when sending the email
# footer_text: |
# Copyright © 2025 Your Name<br>
# 123 Main St<br>
# City, State ZIP
#
# <webversion>View on the web</webversion> | <unsubscribe>Unsubscribe</unsubscribe>
# File Paths
paths:
template_file: 'email-template.html'
styles_file: 'styles.css'
# Markdown Processor
markdown:
processor: 'apex' # or 'pandoc', 'kramdown', etc.

View file

@ -0,0 +1,55 @@
# Email Generator Configuration
# Copy this file to config.yml and fill in your values
# Sendy API Configuration
sendy:
api_url: ''
api_key: ''
brand_id: ''
list_ids: ''
# Email Settings
email:
from_name: 'Pascal Le Merrer'
from_email: 'contact@craftletter.fr'
reply_to: 'contact@craftletter.fr'
# Campaign Settings
campaign:
track_opens: '0'
track_clicks: '0'
default_timezone: 'Europe/Paris'
# Template Settings
template:
header_image_url: 'https://www.craftletter.fr/images/craftletter.svg'
header_image_alt: 'Logo Craft Letter'
header_image_width: 600
header_image_height: 185
signature_image_url: ''
signature_image_alt: ''
signature_image_width: 0
signature_image_height: 0
signature_text: ''
# Optional: Primary footer appears after signature, before unsubscribe section
# Can contain Markdown or HTML (e.g., product links, promotional content)
# primary_footer: |
# [![](/mas.jpg)](example.com "Purchase on the Mac App Store") | [![](/paddle.jpg)](example.com "Purchase directly")
# Footer text - can contain Markdown and will preserve <webversion> and <unsubscribe> tags
# Sendy will replace these tags when sending the email
# footer_text: |
# Copyright © 2025 Your Name<br>
# 123 Main St<br>
# City, State ZIP
#
# <webversion>View on the web</webversion> | <unsubscribe>Unsubscribe</unsubscribe>
# File Paths
paths:
template_file: 'email-template.html'
styles_file: 'styles.css'
# Markdown Processor
markdown:
processor: 'multimarkdown' # or 'apex', pandoc', 'kramdown', etc.

View file

@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{{TITLE}}</title>
<!--[if mso]>
<style type="text/css">
body, table, td {font-family: {{FONT_FAMILY}} !important;}
</style>
<![endif]-->
</head>
<body style="{{BODY_STYLE}}">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="{{WRAPPER_STYLE}}">
<tr>
<td align="center" style="padding: 20px 0;">
<!-- Main Container -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="600"
style="{{CONTENT_WRAPPER_STYLE}}">
<!-- Header Image -->
<tr>
<td align="center" style="padding: 0;">
<img alt="{{HEADER_IMAGE_ALT}}" src="{{HEADER_IMAGE_URL}}" width="{{HEADER_IMAGE_WIDTH}}"
height="{{HEADER_IMAGE_HEIGHT}}"
style="display: block; width: {{HEADER_IMAGE_WIDTH}}px; height: {{HEADER_IMAGE_HEIGHT}}px; border: 0; border-radius: 4px 4px 0 0;" />
</td>
</tr>
<!-- Content Area -->
<tr>
<td style="padding: 40px 40px 30px 40px;">
{{CONTENT}}
<!-- Signature -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td style="padding: 0; height: 20px; line-height: 20px; font-size: 20px; ">&nbsp;
</td>
</tr>
<tr>
<td style="padding: 0;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0">
<tr>
<td style="padding: 0; vertical-align: middle;">
<div style="{{SIGNATURE_STYLE}}">
{{SIGNATURE_TEXT}}
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
{{PRIMARY_FOOTER}}
</td>
</tr>
<!-- Footer -->
<tr>
<td style="{{FOOTER_STYLE}}">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" width="100%">
<tbody style="font-size: 13px; line-height: 1.5; color: #666666; padding: 0">
<tr>
<td align="center" style="padding: 20px 40px;">
<a href="https://www.craftletter.fr">Craft Letter</a> © 2025 par <a href="https://www.linkedin.com/in/pascal-le-merrer/">Pascal Le Merrer</a><br>est sous licence <a href="https://creativecommons.org/licenses/by-nc-nd/4.0/">CC BY-NC-ND 4.0</a></p><div><img alt="" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg" style="max-width:1em;max-height:1em;margin-left:.2em"><img alt="" src="https://mirrors.creativecommons.org/presskit/icons/by.svg" style="max-width:1em;max-height:1em;margin-left:.2em"><img alt="" src="https://mirrors.creativecommons.org/presskit/icons/nc.svg" style="max-width:1em;max-height:1em;margin-left:.2em"><img alt="" src="https://mirrors.creativecommons.org/presskit/icons/nd.svg" style="max-width:1em;max-height:1em;margin-left:.2em">
</td>
</tr>
<tr>
<td align="center">
<a href="{{ unsubscribe_link }}" style="color: #000000; font-family: Arial, Helvetica, sans-serif; font-size: 12px; text-decoration: underline;">Se désabonner</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

240
mdtosendy_config/styles.css Normal file
View file

@ -0,0 +1,240 @@
/* Email Styles Configuration
* These styles will be converted to inline styles for email compatibility
*/
/* Body and wrapper styles */
body {
margin: 0;
padding: 0;
/* background: linear-gradient(to bottom, #0a1a26, #0f3d5f); */
background-color: #ffffff;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
}
.content-wrapper {
background-color: #ffffff;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
padding: 20px;
text-align: justify;
}
/* Typography */
h1 {
text-align: center;
margin: 2rem 0 2rem 0;
padding: 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 28px;
font-weight: bold;
color: #333333;
line-height: 1.3;
}
h1 td {
padding: 0 0 20px 0;
}
h2 {
margin: 0;
padding: 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 24px;
font-weight: bold;
color: #333333;
line-height: 1.3;
}
h2 td {
padding: 0 0 20px 0;
}
h3 {
margin: 0;
padding: 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 20px;
font-weight: bold;
color: #333333;
line-height: 1.3;
}
h3 td {
padding: 0 0 15px 0;
}
p {
margin: 0;
padding: 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
}
p td {
padding: 0 0 20px 0;
text-align: justify;
}
/* Links */
a {
color: #0066cc;
text-decoration: underline;
}
/* Buttons */
a.button {
display: inline-block;
padding: 16px 40px;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 18px;
font-weight: bold;
color: #ffffff !important;
text-decoration: none !important;
border-radius: 16px;
background: linear-gradient(to right, #ff9f5a, #ff6b1a);
background-color: #ff6b1a;
border: 1px solid #e85a00;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
a.button span {
color: #ffffff;
font-weight: bold;
text-decoration: none;
}
a.button td {
background: linear-gradient(to right, #ff9f5a, #ff6b1a);
background-color: #ff6b1a;
border-radius: 16px;
padding: 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
a.button-wrapper {
padding: 0 0 20px 0;
}
a.button-fallback {
padding: 0 0 25px 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 14px;
line-height: 1.6;
color: #666666;
}
a.button-fallback a {
color: #0066cc;
text-decoration: underline;
font-size: 13px;
}
/* Images */
img {
max-width: 100%;
height: auto;
border: 0;
}
img.full-width {
display: block;
margin: 1em 0;
}
img.float-left {
max-width: 30%;
float: left;
margin: 0 1em 1em 0;
}
img.float-right {
max-width: 30%;
float: right;
margin: 0 0 1em 1em;
}
/* Lists */
ul,
ol {
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
}
ul td,
ol td {
padding: 0 0 10px 0;
}
li {
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
}
li td {
padding: 0 0 8px 0;
}
li.bullet {
width: 20px;
vertical-align: top;
color: #333333;
}
li.content {
padding: 0 0 8px 0;
vertical-align: top;
}
/* Text formatting */
strong,
b {
font-weight: bold;
}
em,
i {
font-style: italic;
}
/* Footer */
.footer {
background-color: #f9f9f9;
border-top: 1px solid #e5e5e5;
border-radius: 0 0 4px 4px;
padding: 30px 40px;
}
.footer p {
font-size: 13px;
line-height: 1.5;
color: #666666;
padding: 0;
}
.footer p:first-child {
padding: 0 0 10px 0;
}
/* Signature */
.signature {
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
padding-top: 20px; /* This padding-top is applied to the signature table cell */
}
.signature img {
width: 98px;
height: 98px;
border-radius: 50%;
border: 0;
display: block;
}

View file

@ -0,0 +1,240 @@
/* Email Styles Configuration
* These styles will be converted to inline styles for email compatibility
*/
/* Body and wrapper styles */
body {
margin: 0;
padding: 0;
background: linear-gradient(to bottom, #0a1a26, #0f3d5f);
background-color: #0a1a26;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
}
.wrapper {
background: linear-gradient(to bottom, #0a1a26, #0f3d5f);
background-color: #0a1a26;
}
.content-wrapper {
background-color: #ffffff;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Typography */
h1 {
margin: 0;
padding: 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 28px;
font-weight: bold;
color: #333333;
line-height: 1.3;
}
h1 td {
padding: 0 0 20px 0;
}
h2 {
margin: 0;
padding: 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 28px;
font-weight: bold;
color: #333333;
line-height: 1.3;
}
h2 td {
padding: 0 0 20px 0;
}
h3 {
margin: 0;
padding: 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 20px;
font-weight: bold;
color: #333333;
line-height: 1.3;
}
h3 td {
padding: 0 0 15px 0;
}
p {
margin: 0;
padding: 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
}
p td {
padding: 0 0 20px 0;
}
/* Links */
a {
color: #0066cc;
text-decoration: underline;
}
/* Buttons */
a.button {
display: inline-block;
padding: 16px 40px;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 18px;
font-weight: bold;
color: #ffffff !important;
text-decoration: none !important;
border-radius: 16px;
background: linear-gradient(to right, #ff9f5a, #ff6b1a);
background-color: #ff6b1a;
border: 1px solid #e85a00;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
a.button span {
color: #ffffff;
font-weight: bold;
text-decoration: none;
}
a.button td {
background: linear-gradient(to right, #ff9f5a, #ff6b1a);
background-color: #ff6b1a;
border-radius: 16px;
padding: 0;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
a.button-wrapper {
padding: 0 0 20px 0;
}
a.button-fallback {
padding: 0 0 25px 0;
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 14px;
line-height: 1.6;
color: #666666;
}
a.button-fallback a {
color: #0066cc;
text-decoration: underline;
font-size: 13px;
}
/* Images */
img {
max-width: 100%;
height: auto;
border: 0;
}
img.full-width {
display: block;
margin: 1em 0;
}
img.float-left {
max-width: 30%;
float: left;
margin: 0 1em 1em 0;
}
img.float-right {
max-width: 30%;
float: right;
margin: 0 0 1em 1em;
}
/* Lists */
ul,
ol {
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
}
ul td,
ol td {
padding: 0 0 10px 0;
}
li {
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
}
li td {
padding: 0 0 8px 0;
}
li.bullet {
width: 20px;
vertical-align: top;
color: #333333;
}
li.content {
padding: 0 0 8px 0;
vertical-align: top;
}
/* Text formatting */
strong,
b {
font-weight: bold;
}
em,
i {
font-style: italic;
}
/* Footer */
.footer {
background-color: #f9f9f9;
border-top: 1px solid #e5e5e5;
border-radius: 0 0 4px 4px;
padding: 30px 40px;
}
.footer p {
font-size: 13px;
line-height: 1.5;
color: #666666;
padding: 0;
}
.footer p:first-child {
padding: 0 0 10px 0;
}
/* Signature */
.signature {
font-family: Avenir, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
font-size: 16px;
line-height: 1.6;
color: #333333;
padding-top: 20px; /* This padding-top is applied to the signature table cell */
}
.signature img {
width: 98px;
height: 98px;
border-radius: 50%;
border: 0;
display: block;
}