newsletter-publishing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseNewsletter publishing
新闻通讯发布
Practical workflows for building and managing email newsletters for journalism and academia.
面向新闻与学术领域的电子邮件通讯构建与管理实用工作流。
When to activate
适用场景
- Creating a new newsletter from scratch
- Designing email templates for journalism content
- Building and segmenting subscriber lists
- Analyzing newsletter performance metrics
- Planning editorial calendars for newsletters
- Migrating between newsletter platforms
- Improving deliverability and open rates
- 从零开始创建新的新闻通讯
- 为新闻内容设计邮件模板
- 构建并细分订阅者列表
- 分析新闻通讯绩效指标
- 规划新闻通讯编辑日历
- 在不同通讯平台间迁移
- 提升送达率与打开率
Newsletter architecture
新闻通讯架构
Content strategy framework
内容策略框架
markdown
undefinedmarkdown
undefinedNewsletter strategy document
新闻通讯策略文档
Core identity
核心定位
- Name:
- Tagline (one line):
- What readers get: [specific value proposition]
- Frequency: [ ] Daily [ ] Weekly [ ] Bi-weekly [ ] Monthly
- 名称:
- 标语(一句话):
- 读者收益: [具体价值主张]
- 发送频率: [ ] 每日 [ ] 每周 [ ] 每两周 [ ] 每月
Target audience
目标受众
- Primary reader:
- What they care about:
- Why they'll subscribe:
- What they'll do with this info:
- 核心读者:
- 他们关注的内容:
- 订阅动机:
- 他们会如何使用这些信息:
Content pillars
内容支柱
- [Core topic 1] - [how often]
- [Core topic 2] - [how often]
- [Recurring feature] - [how often]
- [核心主题1] - [更新频率]
- [核心主题2] - [更新频率]
- [固定栏目] - [更新频率]
Voice and tone
语气风格
- Formal ↔ Conversational: [1-5]
- Serious ↔ Light: [1-5]
- Reported ↔ Personal: [1-5]
- 正式 ↔ 口语化: [1-5]
- 严肃 ↔ 轻松: [1-5]
- 客观报道 ↔ 个人观点: [1-5]
Success metrics (first 6 months)
初期成功指标(前6个月)
- Subscriber goal:
- Target open rate:
- Target click rate:
undefined- 订阅者目标:
- 目标打开率:
- 目标点击率:
undefinedIssue structure template
单期通讯结构模板
markdown
undefinedmarkdown
undefined[Newsletter Name] - Issue #[XX]
[新闻通讯名称] - 第#[XX]期
Date: [Date]
Subject line: [Subject]
Preview text: [First 50-90 characters readers see]
日期: [日期]
主题: [主题]
预览文本: [读者会看到的前50-90个字符]
Opening hook
开篇钩子
[2-3 sentences that make readers want to keep reading]
[2-3句话,吸引读者继续阅读]
Main story
主要内容
[Your primary content - 300-600 words for most newsletters]
[核心内容 - 大多数通讯建议300-600字]
Secondary items (if applicable)
次要内容(可选)
- Quick hit 1: [Brief item with link]
- Quick hit 2: [Brief item with link]
- 速览1: [带链接的简短内容]
- 速览2: [带链接的简短内容]
Recurring section
固定栏目
[Weekly column, data point, recommendation, etc.]
[每周专栏、数据点、推荐内容等]
Sign-off
结尾
[Personal note, call to action, or preview of next issue]
Unsubscribe | Preferences | Forward to a friend
undefined[个人留言、行动号召或下期预告]
取消订阅 | 偏好设置 | 转发给好友
undefinedTechnical implementation
技术实现
HTML email template (responsive)
响应式HTML邮件模板
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{newsletter_name}}</title>
<style>
/* Reset styles for email clients */
body { margin: 0; padding: 0; width: 100%; }
table { border-collapse: collapse; }
img { border: 0; display: block; }
/* Responsive container */
.container {
max-width: 600px;
margin: 0 auto;
font-family: Georgia, serif;
font-size: 18px;
line-height: 1.6;
color: #333;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.container { background-color: #1a1a1a; color: #e0e0e0; }
a { color: #6db3f2; }
}
/* Mobile styles */
@media only screen and (max-width: 480px) {
.container { padding: 15px !important; }
h1 { font-size: 24px !important; }
}
</style>
</head>
<body>
<table role="presentation" width="100%">
<tr>
<td align="center" style="padding: 20px;">
<div class="container">
<!-- Header -->
<table width="100%">
<tr>
<td style="padding-bottom: 20px; border-bottom: 2px solid #333;">
<h1 style="margin: 0;">{{newsletter_name}}</h1>
<p style="margin: 5px 0 0; color: #666;">{{issue_date}}</p>
</td>
</tr>
</table>
<!-- Content -->
<table width="100%">
<tr>
<td style="padding: 30px 0;">
{{content}}
</td>
</tr>
</table>
<!-- Footer -->
<table width="100%">
<tr>
<td style="padding-top: 20px; border-top: 1px solid #ddd; font-size: 14px; color: #666;">
<p>You're receiving this because you subscribed to {{newsletter_name}}.</p>
<p>
<a href="{{unsubscribe_url}}">Unsubscribe</a> |
<a href="{{preferences_url}}">Update preferences</a>
</p>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</body>
</html>html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{newsletter_name}}</title>
<style>
/* Reset styles for email clients */
body { margin: 0; padding: 0; width: 100%; }
table { border-collapse: collapse; }
img { border: 0; display: block; }
/* Responsive container */
.container {
max-width: 600px;
margin: 0 auto;
font-family: Georgia, serif;
font-size: 18px;
line-height: 1.6;
color: #333;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.container { background-color: #1a1a1a; color: #e0e0e0; }
a { color: #6db3f2; }
}
/* Mobile styles */
@media only screen and (max-width: 480px) {
.container { padding: 15px !important; }
h1 { font-size: 24px !important; }
}
</style>
</head>
<body>
<table role="presentation" width="100%">
<tr>
<td align="center" style="padding: 20px;">
<div class="container">
<!-- Header -->
<table width="100%">
<tr>
<td style="padding-bottom: 20px; border-bottom: 2px solid #333;">
<h1 style="margin: 0;">{{newsletter_name}}</h1>
<p style="margin: 5px 0 0; color: #666;">{{issue_date}}</p>
</td>
</tr>
</table>
<!-- Content -->
<table width="100%">
<tr>
<td style="padding: 30px 0;">
{{content}}
</td>
</tr>
</table>
<!-- Footer -->
<table width="100%">
<tr>
<td style="padding-top: 20px; border-top: 1px solid #ddd; font-size: 14px; color: #666;">
<p>You're receiving this because you subscribed to {{newsletter_name}}.</p>
<p>
<a href="{{unsubscribe_url}}">Unsubscribe</a> |
<a href="{{preferences_url}}">Update preferences</a>
</p>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</body>
</html>Python newsletter sender
Python新闻通讯发送器
python
from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Dict, Optional
from enum import Enum
import hashlib
class SubscriberStatus(Enum):
ACTIVE = "active"
UNSUBSCRIBED = "unsubscribed"
BOUNCED = "bounced"
COMPLAINED = "complained"
@dataclass
class Subscriber:
email: str
name: Optional[str] = None
subscribed_at: datetime = field(default_factory=datetime.now)
status: SubscriberStatus = SubscriberStatus.ACTIVE
tags: List[str] = field(default_factory=list)
custom_fields: Dict = field(default_factory=dict)
@property
def hash_id(self) -> str:
"""Generate unique ID for unsubscribe links."""
return hashlib.md5(self.email.encode()).hexdigest()[:12]
@dataclass
class NewsletterIssue:
subject: str
preview_text: str
html_content: str
plain_text: str
scheduled_at: Optional[datetime] = None
sent_at: Optional[datetime] = None
issue_number: int = 0
# Metrics
sent_count: int = 0
delivered_count: int = 0
opened_count: int = 0
clicked_count: int = 0
bounced_count: int = 0
unsubscribed_count: int = 0
@property
def open_rate(self) -> float:
if self.delivered_count == 0:
return 0.0
return (self.opened_count / self.delivered_count) * 100
@property
def click_rate(self) -> float:
if self.delivered_count == 0:
return 0.0
return (self.clicked_count / self.delivered_count) * 100
class NewsletterManager:
"""Core newsletter operations."""
def __init__(self, name: str):
self.name = name
self.subscribers: List[Subscriber] = []
self.issues: List[NewsletterIssue] = []
def add_subscriber(self, email: str, name: str = None,
tags: List[str] = None) -> Subscriber:
"""Add new subscriber with double opt-in pending."""
sub = Subscriber(
email=email.lower().strip(),
name=name,
tags=tags or []
)
self.subscribers.append(sub)
return sub
def segment_subscribers(self, tags: List[str] = None,
min_engagement: float = None) -> List[Subscriber]:
"""Get subscribers matching criteria."""
active = [s for s in self.subscribers
if s.status == SubscriberStatus.ACTIVE]
if tags:
active = [s for s in active
if any(t in s.tags for t in tags)]
return active
def calculate_engagement_score(self, subscriber: Subscriber) -> float:
"""Score subscriber engagement 0-100."""
# Implementation would track opens/clicks per subscriber
return 50.0 # Placeholderpython
from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Dict, Optional
from enum import Enum
import hashlib
class SubscriberStatus(Enum):
ACTIVE = "active"
UNSUBSCRIBED = "unsubscribed"
BOUNCED = "bounced"
COMPLAINED = "complained"
@dataclass
class Subscriber:
email: str
name: Optional[str] = None
subscribed_at: datetime = field(default_factory=datetime.now)
status: SubscriberStatus = SubscriberStatus.ACTIVE
tags: List[str] = field(default_factory=list)
custom_fields: Dict = field(default_factory=dict)
@property
def hash_id(self) -> str:
"""Generate unique ID for unsubscribe links."""
return hashlib.md5(self.email.encode()).hexdigest()[:12]
@dataclass
class NewsletterIssue:
subject: str
preview_text: str
html_content: str
plain_text: str
scheduled_at: Optional[datetime] = None
sent_at: Optional[datetime] = None
issue_number: int = 0
# Metrics
sent_count: int = 0
delivered_count: int = 0
opened_count: int = 0
clicked_count: int = 0
bounced_count: int = 0
unsubscribed_count: int = 0
@property
def open_rate(self) -> float:
if self.delivered_count == 0:
return 0.0
return (self.opened_count / self.delivered_count) * 100
@property
def click_rate(self) -> float:
if self.delivered_count == 0:
return 0.0
return (self.clicked_count / self.delivered_count) * 100
class NewsletterManager:
"""Core newsletter operations."""
def __init__(self, name: str):
self.name = name
self.subscribers: List[Subscriber] = []
self.issues: List[NewsletterIssue] = []
def add_subscriber(self, email: str, name: str = None,
tags: List[str] = None) -> Subscriber:
"""Add new subscriber with double opt-in pending."""
sub = Subscriber(
email=email.lower().strip(),
name=name,
tags=tags or []
)
self.subscribers.append(sub)
return sub
def segment_subscribers(self, tags: List[str] = None,
min_engagement: float = None) -> List[Subscriber]:
"""Get subscribers matching criteria."""
active = [s for s in self.subscribers
if s.status == SubscriberStatus.ACTIVE]
if tags:
active = [s for s in active
if any(t in s.tags for t in tags)]
return active
def calculate_engagement_score(self, subscriber: Subscriber) -> float:
"""Score subscriber engagement 0-100."""
# Implementation would track opens/clicks per subscriber
return 50.0 # PlaceholderSubscriber management
订阅者管理
List hygiene workflow
列表清理工作流
python
from datetime import datetime, timedelta
def clean_subscriber_list(manager: NewsletterManager,
inactive_threshold_days: int = 180) -> dict:
"""Identify and handle inactive subscribers."""
cutoff = datetime.now() - timedelta(days=inactive_threshold_days)
results = {
'total': len(manager.subscribers),
'active': 0,
'inactive': [],
'bounced': [],
'unsubscribed': []
}
for sub in manager.subscribers:
if sub.status == SubscriberStatus.BOUNCED:
results['bounced'].append(sub.email)
elif sub.status == SubscriberStatus.UNSUBSCRIBED:
results['unsubscribed'].append(sub.email)
elif sub.status == SubscriberStatus.ACTIVE:
# Check last engagement
engagement = manager.calculate_engagement_score(sub)
if engagement < 10: # Very low engagement
results['inactive'].append(sub.email)
else:
results['active'] += 1
return results
def run_reengagement_campaign(inactive_subscribers: List[str]) -> None:
"""Send win-back campaign to inactive subscribers."""
# Send "We miss you" campaign
# If no engagement after 2 attempts, mark for removal
passpython
from datetime import datetime, timedelta
def clean_subscriber_list(manager: NewsletterManager,
inactive_threshold_days: int = 180) -> dict:
"""Identify and handle inactive subscribers."""
cutoff = datetime.now() - timedelta(days=inactive_threshold_days)
results = {
'total': len(manager.subscribers),
'active': 0,
'inactive': [],
'bounced': [],
'unsubscribed': []
}
for sub in manager.subscribers:
if sub.status == SubscriberStatus.BOUNCED:
results['bounced'].append(sub.email)
elif sub.status == SubscriberStatus.UNSUBSCRIBED:
results['unsubscribed'].append(sub.email)
elif sub.status == SubscriberStatus.ACTIVE:
# Check last engagement
engagement = manager.calculate_engagement_score(sub)
if engagement < 10: # Very low engagement
results['inactive'].append(sub.email)
else:
results['active'] += 1
return results
def run_reengagement_campaign(inactive_subscribers: List[str]) -> None:
"""Send win-back campaign to inactive subscribers."""
# Send "We miss you" campaign
# If no engagement after 2 attempts, mark for removal
passSubscriber segmentation
订阅者细分
markdown
undefinedmarkdown
undefinedRecommended segments
推荐细分维度
By engagement
按参与度
- VIPs: Open rate > 80%, always click
- Engaged: Open rate 40-80%
- Casual: Open rate 10-40%
- At-risk: Haven't opened in 90 days
- Inactive: Haven't opened in 180 days
- 核心用户: 打开率>80%,每次都点击
- 活跃用户: 打开率40-80%
- 普通用户: 打开率10-40%
- 风险用户: 90天未打开
- 沉睡用户: 180天未打开
By interest (tag-based)
按兴趣(基于标签)
- Topic preferences from signup
- Content they've clicked
- Surveys/polls they've answered
- 注册时选择的主题偏好
- 点击过的内容
- 参与过的调研/投票
By source
按来源
- Organic (website signup)
- Referral (forwarded by friend)
- Social media
- Paywall/registration wall
undefined- 自然流量(官网注册)
- 推荐(好友转发)
- 社交媒体
- 付费墙/注册墙
undefinedSubject line optimization
主题行优化
High-performing patterns
高绩效主题行模式
markdown
undefinedmarkdown
undefinedSubject line formulas that work
有效的主题行公式
For news/journalism
新闻/资讯类
- Breaking format: "Breaking: [Concise news]"
- Numbers: "[X] things we learned about [topic]"
- Question: "Why did [entity] do [thing]?"
- Direct: "[Topic]: What you need to know"
- 突发格式: "突发:[简洁新闻内容]"
- 数字型: "关于[主题]的[X]个关键发现"
- 疑问型: "为什么[主体]会做出[行为]?"
- 直接型: "[主题]:你需要了解的内容"
For analysis/opinion
分析/观点类
- Take: "The real story behind [event]"
- Contrarian: "Why everyone is wrong about [topic]"
- Insider: "What [industry] insiders know about [topic]"
- 深度解读: "[事件]背后的真相"
- 逆向观点: "为什么所有人都误解了[主题]"
- 内部视角: "[行业]从业者才知道的[主题]内幕"
What to avoid
需避免的雷区
- ALL CAPS
- Excessive punctuation!!!
- Clickbait that doesn't deliver
- Spam trigger words (FREE, URGENT, ACT NOW)
- Misleading preview text
undefined- 全大写字母
- 过多标点符号!!!
- 无法兑现的标题党
- 垃圾邮件触发词(FREE、URGENT、ACT NOW)
- 误导性预览文本
undefinedA/B testing framework
A/B测试框架
python
import random
from typing import List, Tuple
def ab_test_subject_lines(subscribers: List[Subscriber],
subject_a: str,
subject_b: str,
test_percentage: float = 0.2) -> dict:
"""
Test two subject lines on subset before full send.
"""
test_size = int(len(subscribers) * test_percentage)
test_group = random.sample(subscribers, test_size)
# Split test group
half = len(test_group) // 2
group_a = test_group[:half]
group_b = test_group[half:]
remaining = [s for s in subscribers if s not in test_group]
return {
'group_a': {
'subject': subject_a,
'subscribers': group_a,
'size': len(group_a)
},
'group_b': {
'subject': subject_b,
'subscribers': group_b,
'size': len(group_b)
},
'remaining': {
'subscribers': remaining,
'size': len(remaining),
'note': 'Send winner to this group after test period'
},
'test_duration_hours': 4
}python
import random
from typing import List, Tuple
def ab_test_subject_lines(subscribers: List[Subscriber],
subject_a: str,
subject_b: str,
test_percentage: float = 0.2) -> dict:
"""
Test two subject lines on subset before full send.
"""
test_size = int(len(subscribers) * test_percentage)
test_group = random.sample(subscribers, test_size)
# Split test group
half = len(test_group) // 2
group_a = test_group[:half]
group_b = test_group[half:]
remaining = [s for s in subscribers if s not in test_group]
return {
'group_a': {
'subject': subject_a,
'subscribers': group_a,
'size': len(group_a)
},
'group_b': {
'subject': subject_b,
'subscribers': group_b,
'size': len(group_b)
},
'remaining': {
'subscribers': remaining,
'size': len(remaining),
'note': 'Send winner to this group after test period'
},
'test_duration_hours': 4
}Deliverability best practices
送达率最佳实践
Email authentication setup
邮件认证设置
markdown
undefinedmarkdown
undefinedDNS records for deliverability
提升送达率的DNS记录
SPF record
SPF记录
v=spf1 include:_spf.youresp.com ~allv=spf1 include:_spf.youresp.com ~allDKIM
DKIM
- Generate keys through your ESP
- Add TXT record with public key
- Verify signature is applied to outgoing mail
- 通过邮件服务提供商(ESP)生成密钥
- 添加包含公钥的TXT记录
- 验证签名已应用于 outgoing 邮件
DMARC
DMARC
v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.comv=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.comChecklist before sending
发送前检查清单
- SPF, DKIM, DMARC configured
- Sending domain warmed up
- List is clean (no hard bounces)
- Unsubscribe link works
- Physical address in footer (CAN-SPAM)
- Test email received in inbox (not spam)
undefined- 已配置SPF、DKIM、DMARC
- 发送域名已完成预热
- 列表已清理(无硬退信)
- 取消订阅链接可用
- 页脚包含物理地址(符合CAN-SPAM)
- 测试邮件已进入收件箱(而非垃圾邮件)
undefinedSpam score checklist
垃圾邮件评分检查清单
markdown
undefinedmarkdown
undefinedBefore you send
发送前检查
Content checks
内容检查
- No spam trigger words
- Text-to-image ratio good (mostly text)
- All links are to reputable domains
- No URL shorteners (use full links)
- Plain text version included
- 无垃圾邮件触发词
- 文本与图片比例合理(以文本为主)
- 所有链接指向可信域名
- 不使用短链接(使用完整链接)
- 包含纯文本版本
Technical checks
技术检查
- From address matches sending domain
- Reply-to address is monitored
- Preheader text is set
- Images have alt text
- Links are not broken
undefined- 发件人地址与发送域名匹配
- 回复地址已被监控
- 已设置预览文本
- 图片包含替代文本
- 链接无失效
undefinedAnalytics and optimization
分析与优化
Key metrics dashboard
核心指标仪表盘
python
from dataclasses import dataclass
@dataclass
class NewsletterAnalytics:
"""Track newsletter performance over time."""
issue: NewsletterIssue
def summary(self) -> dict:
return {
'issue_number': self.issue.issue_number,
'sent': self.issue.sent_count,
'delivered': self.issue.delivered_count,
'delivery_rate': self._pct(self.issue.delivered_count,
self.issue.sent_count),
'opens': self.issue.opened_count,
'open_rate': self.issue.open_rate,
'clicks': self.issue.clicked_count,
'click_rate': self.issue.click_rate,
'click_to_open': self._pct(self.issue.clicked_count,
self.issue.opened_count),
'unsubscribes': self.issue.unsubscribed_count,
'unsubscribe_rate': self._pct(self.issue.unsubscribed_count,
self.issue.delivered_count),
}
def _pct(self, numerator: int, denominator: int) -> float:
if denominator == 0:
return 0.0
return round((numerator / denominator) * 100, 2)python
from dataclasses import dataclass
@dataclass
class NewsletterAnalytics:
"""Track newsletter performance over time."""
issue: NewsletterIssue
def summary(self) -> dict:
return {
'issue_number': self.issue.issue_number,
'sent': self.issue.sent_count,
'delivered': self.issue.delivered_count,
'delivery_rate': self._pct(self.issue.delivered_count,
self.issue.sent_count),
'opens': self.issue.opened_count,
'open_rate': self.issue.open_rate,
'clicks': self.issue.clicked_count,
'click_rate': self.issue.click_rate,
'click_to_open': self._pct(self.issue.clicked_count,
self.issue.opened_count),
'unsubscribes': self.issue.unsubscribed_count,
'unsubscribe_rate': self._pct(self.issue.unsubscribed_count,
self.issue.delivered_count),
}
def _pct(self, numerator: int, denominator: int) -> float:
if denominator == 0:
return 0.0
return round((numerator / denominator) * 100, 2)Benchmarks (journalism newsletters)
Benchmarks (journalism newsletters)
BENCHMARKS = {
'open_rate': {'good': 40, 'excellent': 55},
'click_rate': {'good': 4, 'excellent': 8},
'unsubscribe_rate': {'acceptable': 0.5, 'concerning': 1.0},
}
undefinedBENCHMARKS = {
'open_rate': {'good': 40, 'excellent': 55},
'click_rate': {'good': 4, 'excellent': 8},
'unsubscribe_rate': {'acceptable': 0.5, 'concerning': 1.0},
}
undefinedPlatform comparison
平台对比
| Platform | Best for | Pricing model | Key feature |
|---|---|---|---|
| Substack | Writer-first, paid subs | Revenue share | Built-in payments |
| Buttondown | Developers, minimal | Per subscriber | Markdown native |
| Ghost | Publishers, memberships | Flat fee | Full CMS included |
| beehiiv | Growth-focused | Freemium | Referral tools |
| ConvertKit | Creators | Per subscriber | Automation |
| Mailchimp | Small orgs | Tiered | Easy templates |
| 平台 | 适用场景 | 定价模式 | 核心功能 |
|---|---|---|---|
| Substack | 以写作者为核心,支持付费订阅 | 收入分成 | 内置支付功能 |
| Buttondown | 开发者群体,极简风格 | 按订阅者数量付费 | 原生支持Markdown |
| Ghost | 出版机构,会员体系 | 固定费用 | 集成完整CMS |
| beehiiv | 增长导向的运营者 | 免费增值模式 | 推荐裂变工具 |
| ConvertKit | 内容创作者 | 按订阅者数量付费 | 自动化工作流 |
| Mailchimp | 小型机构 | 分层定价 | 易用模板库 |
Legal compliance
合规要求
CAN-SPAM requirements (US)
美国CAN-SPAM合规要求
markdown
- [ ] Accurate "From" name and email
- [ ] Non-deceptive subject line
- [ ] Physical postal address included
- [ ] Working unsubscribe mechanism
- [ ] Unsubscribe honored within 10 days
- [ ] No purchased listsmarkdown
- [ ] 发件人名称与邮箱地址准确
- [ ] 主题行无欺骗性
- [ ] 包含物理邮寄地址
- [ ] 提供可用的取消订阅机制
- [ ] 10天内处理取消订阅请求
- [ ] 不使用购买的邮件列表GDPR requirements (EU subscribers)
欧盟GDPR合规要求(针对欧盟订阅者)
markdown
- [ ] Explicit consent obtained (not pre-checked)
- [ ] Clear privacy policy linked
- [ ] Easy unsubscribe process
- [ ] Data export available on request
- [ ] Data deletion on request
- [ ] Record of consent storedmarkdown
- [ ] 获取明确的订阅许可(非预先勾选)
- [ ] 链接清晰的隐私政策
- [ ] 提供便捷的取消订阅流程
- [ ] 可应请求导出用户数据
- [ ] 可应请求删除用户数据
- [ ] 留存订阅许可记录Related skills
相关技能
- web-scraping - Automate content gathering for newsletters
- data-journalism - Include data visualizations in emails
- academic-writing - Write clear, structured content
- 网页爬取 - 自动收集通讯内容
- 数据新闻 - 在邮件中加入数据可视化内容
- 学术写作 - 撰写清晰、结构化的内容
Skill metadata
技能元数据
| Field | Value |
|---|---|
| Version | 1.0.0 |
| Created | 2025-12-26 |
| Author | Claude Skills for Journalism |
| Domain | Publishing, Marketing |
| Complexity | Intermediate |
| 字段 | 值 |
|---|---|
| 版本 | 1.0.0 |
| 创建时间 | 2025-12-26 |
| 作者 | Claude Skills for Journalism |
| 领域 | 出版、营销 |
| 复杂度 | 中级 |