← back to Dw Mailer Glitter Naturals Custom
build.py
234 lines
#!/usr/bin/env python3
"""
Build the DW "New Arrivals" Constant Contact mailer (TK-11836).
Structure is cloned verbatim from the last DW send
(~/Projects/dw-vendor-mailer/mailer.html — "The Houses We Represent",
2026-09-09..16): 600px table-based, inline-styled, email-client-safe.
This edition refreshes the lineup to FOUR DW-owned / private-label lines Steve
asked to feature, and adds a full-bleed ROOM-SETTING hero at the top:
1. Glitter Walls (glitter / sequin / glass-bead line)
2. Fentucci Naturals (private label — real vendor NEVER customer-facing)
3. Phillipe Romano Naturals (private label — real vendors NEVER customer-facing)
4. Custom & Bespoke (made-to-order CTA block)
The DW logo masthead AND the hero room image both link to
/collections/new-arrivals (Steve: "make sure dw banner clicks to new arrivals").
Every product page, collection/page link, and image URL below verified HTTP 200
on 2026-09-16 (www.designerwallcoverings.com canonical).
Regenerate: python3 build.py -> mailer.html
LEAK RULE: no upstream/true-vendor name (Tokiwa, Greenland, Command54, WallQuest,
Chesapeake, Momentum, Versa, etc.) appears anywhere in copy, alt, or filenames.
Only customer-facing brand names (Fentucci, Phillipe Romano, Glitter Walls) are used.
"""
import html, pathlib
STORE = "https://www.designerwallcoverings.com"
NEW_ARRIVALS = STORE + "/collections/new-arrivals"
DW_LOGO = "https://www.designerwallcoverings.com/cdn/shop/files/Screen_Shot_2019-02-06_at_12.08.24_PM_525x300.png?v=1613539653"
# Full-bleed room-setting hero (real DW lifestyle render, landscape 1184x771).
HERO_IMG = "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/medici-real-cork-damask-wallpaper-cork-92713-living_room.jpg?v=1775084704"
INK = "#221f1c"
MUTED = "#8a8178"
LINE = "#e7e2db"
CREAM = "#f7f5f2"
SERIF = "'Playfair Display', Georgia, 'Times New Roman', serif"
SANS = "-apple-system, 'Helvetica Neue', Arial, sans-serif"
# Grid sections: display name (live serif wordmark — these are DW house / private
# labels, so a text wordmark IS the brand mark, exactly as PR is defined in the base),
# tagline, collection handle, and 4 products (caption, product handle, image url).
SECTIONS = [
{
"wordmark": "Glitter Walls",
"wordmark_size": 30,
"tagline": "High-shine sequin & glass-bead walls.",
"collection": "glitter-walls",
"shop_label": "Glitter Walls",
# glm-still-*.jpg = plain still swatches (the -clean.jpg set are video
# poster frames with a baked-in play triangle — wrong for a static email).
"products": [
("Hollywood Glamour Sequin — Silver", "hollywood-glamour-sequin-silver-multi-color-glm-52009",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/glm-still-GLM-52009-SAMPLE.jpg?v=1782431735"),
("Hollywood Glamour Sequin — Blush", "hollywood-glamour-sequin-blush-glm-52000",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/glm-still-GLM-52000-SAMPLE.jpg?v=1782431715"),
("Hollywood Glamour Sequin — Black", "hollywood-glamour-sequin-deep-black-glam-glm-52012",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/glm-still-GLM-52012-SAMPLE.jpg?v=1782431760"),
("Hollywood Glamour Sequin — Fuchsia", "hollywood-glamour-sequin-electric-fuschia-pink-glm-52007",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/glm-still-GLM-52007-SAMPLE.jpg?v=1782431743"),
],
},
{
"wordmark": "Fentucci Naturals",
"wordmark_size": 28,
"tagline": "Handwoven grasscloth & natural texture.",
"collection": "fentucci-naturals",
"shop_label": "Fentucci Naturals",
"products": [
("Napoli — Caramel Basketweave", "napoli-caramel-basketweave-grasscloth-wallcovering-fentucci",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/napoli-caramel-basketweave-grasscloth-wallcovering-fentucci-37227446927411.jpg?v=1785460624"),
("Oliva — Khaki Basketweave", "oliva-khaki-basketweave-grasscloth-wallcovering-fentucci",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/GRS-27580.jpg?v=1776879830"),
("Modena — Gold Basketweave", "modena-gold-basketweave-grasscloth-wallcovering-fentucci",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/GRS-27570.jpg?v=1776879826"),
("Cremona — Parchment Texture", "cremona-parchment-textured-grasscloth-wallcovering-fentucci",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/GRS-27560.jpg?v=1776879822"),
],
},
{
"wordmark": "Phillipe Romano Naturals",
"wordmark_size": 25,
"tagline": "Real cork, mica & natural grounds — from our own atelier.",
"collection": "phillipe-romano-naturals",
"shop_label": "Phillipe Romano Naturals",
"products": [
("Oxel Cork", "oxel-cork-wallpaper-inw-4899",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/files/oxel-cork-wallpaper-inw-4899-4176704045168.jpg?v=1785460958"),
("Million Dollar Mica Chip", "million-dollar-mica-chip-wallpaper-mdm-64006",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/products/86c999e57ca94ffa6d42d7b55020cc1c.jpg?v=1774200201"),
("Corkytown Real Cork", "corkytown-real-cork-wallpaper-cork-98605",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/products/05ff41edbe53075093de08e67597a75c.jpg?v=1775080877"),
("Bella Calabria Mica Herringbone", "bella-calabria-mica-chevron-herringbone-prn-62342",
"https://cdn.shopify.com/s/files/1/0015/4117/7456/products/3c2ac84cbe04bbe26d7c388b57ed702c.jpg?v=1775116939"),
],
},
]
# Custom / bespoke CTA block.
CUSTOM = {
"wordmark": "Custom & Bespoke",
"tagline": "Made to order — murals, bespoke colorways & scale.",
"img": "https://cdn.shopify.com/s/files/1/0015/4117/7456/files/bella-calabria-mica-chevron-herringbone-prn-62342-bedroom.jpg?v=1775117018",
"img_alt": "Custom wallcovering room setting",
"blurb": "Bring us your reference — we match, scale, and print to your specification. Murals, custom colorways, oversized repeats, and specialty grounds, all produced to order.",
"link": STORE + "/pages/custom",
"cta": "Start a Custom Project",
}
def product_cell(name, handle, img):
url = f"{STORE}/products/{handle}"
name_e = html.escape(name)
return f""" <td width="132" valign="top" style="padding:2px;">
<a href="{url}" target="_blank" style="text-decoration:none;color:{INK};">
<img src="{img}" width="128" alt="{name_e}" style="display:block;width:128px;height:128px;object-fit:cover;border:1px solid {LINE};border-radius:3px;background:#fff;">
<div style="font-family:{SANS};font-size:11px;line-height:1.3;color:{INK};padding:5px 2px 0;text-align:center;">{name_e}</div>
</a>
</td>"""
def section_block(v):
ws = v.get("wordmark_size", 30)
header = (f'<div style="font-family:{SERIF};font-weight:600;font-size:{ws}px;'
f'letter-spacing:.3px;color:{INK};">{html.escape(v["wordmark"])}</div>')
cells = "\n".join(product_cell(*p) for p in v["products"])
coll = f"{STORE}/collections/{v['collection']}"
tagline = html.escape(v.get("tagline", ""))
shop = html.escape(v.get("shop_label", v["wordmark"]))
return f"""
<!-- {html.escape(v['wordmark'])} -->
<tr><td style="padding:16px 24px 4px;text-align:center;">
{header}
<div style="font-family:{SANS};font-size:12px;color:{MUTED};padding-top:6px;">{tagline}</div>
</td></tr>
<tr><td style="padding:6px 10px 0;">
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%"><tr>
{cells}
</tr></table>
</td></tr>
<tr><td style="padding:12px 24px 6px;text-align:center;">
<div style="font-family:{SANS};font-size:12px;color:{MUTED};padding-bottom:12px;">Order any pattern as a <strong style="color:{INK};">sample</strong>.</div>
<a href="{coll}" target="_blank" style="display:inline-block;font-family:{SANS};font-size:12px;letter-spacing:1.2px;text-transform:uppercase;color:{INK};text-decoration:none;border:1px solid {INK};padding:10px 26px;border-radius:2px;">Shop {shop} →</a>
</td></tr>
<tr><td style="padding:22px 24px 0;"><div style="border-top:1px solid {LINE};font-size:0;line-height:0;"> </div></td></tr>"""
def custom_block(c):
return f"""
<!-- {html.escape(c['wordmark'])} -->
<tr><td style="padding:16px 24px 4px;text-align:center;">
<div style="font-family:{SERIF};font-weight:600;font-size:30px;letter-spacing:.3px;color:{INK};">{html.escape(c['wordmark'])}</div>
<div style="font-family:{SANS};font-size:12px;color:{MUTED};padding-top:6px;">{html.escape(c['tagline'])}</div>
</td></tr>
<tr><td style="padding:10px 24px 0;">
<a href="{c['link']}" target="_blank" style="text-decoration:none;border:0;">
<img src="{c['img']}" width="552" alt="{html.escape(c['img_alt'])}" style="display:block;width:100%;max-width:552px;height:auto;border:1px solid {LINE};border-radius:3px;">
</a>
</td></tr>
<tr><td style="padding:12px 24px 6px;text-align:center;">
<div style="font-family:{SANS};font-size:12px;line-height:1.55;color:{MUTED};padding:0 6px 14px;">{html.escape(c['blurb'])}</div>
<a href="{c['link']}" target="_blank" style="display:inline-block;font-family:{SANS};font-size:12px;letter-spacing:1.2px;text-transform:uppercase;color:{INK};text-decoration:none;border:1px solid {INK};padding:10px 26px;border-radius:2px;">{html.escape(c['cta'])} →</a>
</td></tr>
<tr><td style="padding:22px 24px 0;"><div style="border-top:1px solid {LINE};font-size:0;line-height:0;"> </div></td></tr>"""
def build():
rows = "".join(section_block(v) for v in SECTIONS) + custom_block(CUSTOM)
doc = f"""<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>New Arrivals — Designer Wallcoverings</title></head>
<body style="margin:0;padding:0;background:{CREAM};">
<div style="display:none;max-height:0;overflow:hidden;opacity:0;">New arrivals across Glitter Walls, Fentucci Naturals, Phillipe Romano Naturals & Custom. Order any pattern as a sample, shipped the same week.</div>
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="background:{CREAM};">
<tr><td align="center" style="padding:24px 12px;">
<table role="presentation" width="600" cellpadding="0" cellspacing="0" border="0" style="width:600px;max-width:600px;background:#ffffff;border:1px solid {LINE};">
<!-- Masthead — logo links to New Arrivals -->
<tr><td style="padding:24px 24px 2px;text-align:center;">
<a href="{NEW_ARRIVALS}" target="_blank" style="text-decoration:none;border:0;">
<img src="{DW_LOGO}" alt="Designer Wallcoverings" width="188" style="display:inline-block;width:188px;max-width:62%;height:auto;border:0;">
</a>
</td></tr>
<tr><td style="padding:2px 24px 12px;text-align:center;">
<a href="{NEW_ARRIVALS}" target="_blank" style="font-family:{SANS};font-size:11px;letter-spacing:3px;text-transform:uppercase;color:{MUTED};text-decoration:none;">Designer Wallcoverings · est. 2003 · to the trade</a>
</td></tr>
<!-- HERO room setting — full-bleed, links to New Arrivals -->
<tr><td style="padding:0;">
<a href="{NEW_ARRIVALS}" target="_blank" style="text-decoration:none;border:0;">
<img src="{HERO_IMG}" width="600" alt="Designer Wallcoverings new arrivals — room setting" style="display:block;width:100%;max-width:600px;height:auto;border:0;">
</a>
</td></tr>
<!-- Headline -->
<tr><td style="padding:20px 24px 4px;text-align:center;">
<div style="font-family:{SERIF};font-size:32px;line-height:1.15;color:{INK};">New Arrivals</div>
<div style="font-family:{SANS};font-size:13px;line-height:1.55;color:{MUTED};padding:10px 18px 0;">A fresh edit across four of our lines — high-shine <strong style="color:{INK};">Glitter Walls</strong>, handwoven <strong style="color:{INK};">Fentucci Naturals</strong>, cork & mica <strong style="color:{INK};">Phillipe Romano Naturals</strong>, and made-to-order <strong style="color:{INK};">Custom</strong>. Order any pattern as a <strong style="color:{INK};">sample</strong>, shipped to your studio the same week.</div>
</td></tr>
<tr><td style="padding:18px 24px 0;"><div style="border-top:2px solid {INK};font-size:0;line-height:0;"> </div></td></tr>
{rows}
<!-- Footer -->
<tr><td style="padding:24px;text-align:center;">
<div style="font-family:{SERIF};font-size:16px;color:{INK};">Designer Wallcoverings</div>
<div style="font-family:{SANS};font-size:11px;line-height:1.7;color:{MUTED};padding-top:8px;">
To the trade · Los Angeles, since 2003<br>
15442 Ventura Blvd · Sherman Oaks, CA 91403 · 1-888-373-4564<br>
<a href="mailto:info@designerwallcoverings.com" style="color:{MUTED};">info@designerwallcoverings.com</a> ·
<a href="{STORE}" target="_blank" style="color:{MUTED};">designerwallcoverings.com</a>
</div>
<div style="font-family:{SANS};font-size:10px;line-height:1.6;color:#b3aa9f;padding-top:14px;">
You're receiving this because you've shopped or registered with Designer Wallcoverings.<br>
Unsubscribe & preference links are added automatically below by Constant Contact.
</div>
</td></tr>
</table>
</td></tr>
</table>
</body></html>"""
out = pathlib.Path(__file__).parent / "mailer.html"
out.write_text(doc, encoding="utf-8")
n_prod = sum(len(s["products"]) for s in SECTIONS)
print(f"wrote {out} ({len(doc):,} bytes) sections={len(SECTIONS)}+custom products={n_prod}")
if __name__ == "__main__":
build()