Brand consistency: emails say "upbeatBytes" (From + digest body)
Per the brand-name standard (camelCase, one word). Updated the SMTP From default and the digest email body/subject strings. Live env From values (auth.env + goodnews.env) updated to match. (Web/OG brand strings in share.py + app.html are the remaining sweep.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+6
-6
@@ -127,7 +127,7 @@ def _item_html(it: dict, base: str) -> str:
|
|||||||
f'<div style="color:#5d6b78;font-size:13px;margin:3px 0 8px">{escape(it["source"])}</div>'
|
f'<div style="color:#5d6b78;font-size:13px;margin:3px 0 8px">{escape(it["source"])}</div>'
|
||||||
f'{summary}{why}'
|
f'{summary}{why}'
|
||||||
'<div style="margin-top:10px;font-size:14px">'
|
'<div style="margin-top:10px;font-size:14px">'
|
||||||
f'<a href="{base}/a/{it["id"]}" style="color:#0083ad;text-decoration:none">Read on Upbeat Bytes</a>'
|
f'<a href="{base}/a/{it["id"]}" style="color:#0083ad;text-decoration:none">Read on upbeatBytes</a>'
|
||||||
f' · <a href="{escape(it["canonical_url"])}" style="color:#5d6b78;text-decoration:none">Full story at source{lock}</a>'
|
f' · <a href="{escape(it["canonical_url"])}" style="color:#5d6b78;text-decoration:none">Full story at source{lock}</a>'
|
||||||
'</div></div>'
|
'</div></div>'
|
||||||
)
|
)
|
||||||
@@ -145,12 +145,12 @@ def build_digest(items: list[dict], brief_date: str, unsub_url: str, base: str |
|
|||||||
followed = followed or []
|
followed = followed or []
|
||||||
n = len(items)
|
n = len(items)
|
||||||
weekday = _weekday(brief_date)
|
weekday = _weekday(brief_date)
|
||||||
subject = f"{weekday}'s Upbeat Bytes · {n} calm read{'' if n == 1 else 's'}"
|
subject = f"{weekday}'s upbeatBytes · {n} calm read{'' if n == 1 else 's'}"
|
||||||
if weekday == "today":
|
if weekday == "today":
|
||||||
subject = f"Today's Upbeat Bytes · {n} calm reads"
|
subject = f"Today's upbeatBytes · {n} calm reads"
|
||||||
|
|
||||||
text_lines = [
|
text_lines = [
|
||||||
f"Upbeat Bytes — Daily Highlights",
|
f"upbeatBytes — Daily Highlights",
|
||||||
f"{n} calm read{'' if n == 1 else 's'} for {weekday}.\n",
|
f"{n} calm read{'' if n == 1 else 's'} for {weekday}.\n",
|
||||||
"Good morning. A small, hopeful handful of what's going right — and there's",
|
"Good morning. A small, hopeful handful of what's going right — and there's",
|
||||||
"always more waiting on the site whenever you want it.\n",
|
"always more waiting on the site whenever you want it.\n",
|
||||||
@@ -181,7 +181,7 @@ def build_digest(items: list[dict], brief_date: str, unsub_url: str, base: str |
|
|||||||
'font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;color:#16263a">'
|
'font-family:-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;color:#16263a">'
|
||||||
# The real logo as a small hosted PNG (SVG isn't email-safe); alt text
|
# The real logo as a small hosted PNG (SVG isn't email-safe); alt text
|
||||||
# keeps the brand when a client blocks remote images.
|
# keeps the brand when a client blocks remote images.
|
||||||
f'<img src="{base}/logo-email.png" alt="Upbeat Bytes" width="180" '
|
f'<img src="{base}/logo-email.png" alt="upbeatBytes" width="180" '
|
||||||
'style="display:block;border:0;outline:none;text-decoration:none;height:auto;margin:0 0 2px">'
|
'style="display:block;border:0;outline:none;text-decoration:none;height:auto;margin:0 0 2px">'
|
||||||
'<div style="font-size:11px;letter-spacing:0.14em;text-transform:uppercase;color:#0083ad;'
|
'<div style="font-size:11px;letter-spacing:0.14em;text-transform:uppercase;color:#0083ad;'
|
||||||
f'margin:5px 0 0">Daily Highlights · {escape(weekday)}</div>'
|
f'margin:5px 0 0">Daily Highlights · {escape(weekday)}</div>'
|
||||||
@@ -192,7 +192,7 @@ def build_digest(items: list[dict], brief_date: str, unsub_url: str, base: str |
|
|||||||
+ main_blocks
|
+ main_blocks
|
||||||
+ followed_html
|
+ followed_html
|
||||||
+ '<p style="font-size:15px;color:#3f7048;margin:8px 0 0">That’s today’s highlights — more good news is '
|
+ '<p style="font-size:15px;color:#3f7048;margin:8px 0 0">That’s today’s highlights — more good news is '
|
||||||
f'always <a href="{base}" style="color:#3f7048">waiting on Upbeat Bytes</a>. See you tomorrow.</p>'
|
f'always <a href="{base}" style="color:#3f7048">waiting on upbeatBytes</a>. See you tomorrow.</p>'
|
||||||
f'<p style="font-size:12px;color:#9aa6b2;margin-top:24px">You’re getting this because you turned on '
|
f'<p style="font-size:12px;color:#9aa6b2;margin-top:24px">You’re getting this because you turned on '
|
||||||
f'the daily digest. <a href="{unsub_url}" style="color:#9aa6b2">Unsubscribe</a>.</p>'
|
f'the daily digest. <a href="{unsub_url}" style="color:#9aa6b2">Unsubscribe</a>.</p>'
|
||||||
'</div>'
|
'</div>'
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ def _cfg() -> dict:
|
|||||||
"port": int(os.environ.get("GOODNEWS_SMTP_PORT", "587")),
|
"port": int(os.environ.get("GOODNEWS_SMTP_PORT", "587")),
|
||||||
"user": os.environ.get("GOODNEWS_SMTP_USER", ""),
|
"user": os.environ.get("GOODNEWS_SMTP_USER", ""),
|
||||||
"password": os.environ.get("GOODNEWS_SMTP_PASSWORD", ""),
|
"password": os.environ.get("GOODNEWS_SMTP_PASSWORD", ""),
|
||||||
"sender": os.environ.get("GOODNEWS_SMTP_FROM", "Upbeat Bytes <hello@upbeatbytes.com>"),
|
"sender": os.environ.get("GOODNEWS_SMTP_FROM", "upbeatBytes <hello@upbeatbytes.com>"),
|
||||||
# Where a reader's reply should land; falls back to the From address.
|
# Where a reader's reply should land; falls back to the From address.
|
||||||
"reply_to": os.environ.get("GOODNEWS_REPLY_TO_EMAIL", ""),
|
"reply_to": os.environ.get("GOODNEWS_REPLY_TO_EMAIL", ""),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ def _seed(c, n=5, date="2026-06-09"):
|
|||||||
def test_build_digest_is_calm_and_dated():
|
def test_build_digest_is_calm_and_dated():
|
||||||
items = [{"id": 1, "title": "Good thing", "canonical_url": "http://a/1", "source": "Src", "summary": "nice", "reason_text": "wonder", "paywalled": False}]
|
items = [{"id": 1, "title": "Good thing", "canonical_url": "http://a/1", "source": "Src", "summary": "nice", "reason_text": "wonder", "paywalled": False}]
|
||||||
subject, text, html = digest.build_digest(items, "2026-06-09", "http://ub/unsub")
|
subject, text, html = digest.build_digest(items, "2026-06-09", "http://ub/unsub")
|
||||||
assert "Tuesday's Upbeat Bytes" in subject and "1 calm read" in subject
|
assert "Tuesday's upbeatBytes" in subject and "1 calm read" in subject
|
||||||
assert "Daily Highlights" in text and "Daily Highlights" in html
|
assert "Daily Highlights" in text and "Daily Highlights" in html
|
||||||
assert "more good news is always" in text and "http://ub/unsub" in text # points back to the site
|
assert "more good news is always" in text and "http://ub/unsub" in text # points back to the site
|
||||||
assert "Good thing" in html and "Read on Upbeat Bytes" in html and "Unsubscribe" in html
|
assert "Good thing" in html and "Read on upbeatBytes" in html and "Unsubscribe" in html
|
||||||
assert "you missed" not in (text + html).lower() # no guilt language
|
assert "you missed" not in (text + html).lower() # no guilt language
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user