- name
- email-marketing-regulations-compliance
- description
- Navigate global email marketing laws (GDPR, CAN-SPAM, CASL, LGPD) with comprehensive regulatory guidance from EmailOctopus
- triggers
- ["check email marketing laws for a country","what are the GDPR requirements for email marketing","do I need consent for email marketing in Canada","CAN-SPAM compliance requirements","email marketing regulations for Brazil","what penalties exist for spam violations","soft opt-in rules for email marketing","verify email marketing compliance"]
# Email Marketing Regulations Compliance
> Skill by [ara.so](https://ara.so) — Marketing Skills collection.
This skill provides access to the comprehensive email marketing regulations repository maintained by EmailOctopus. It contains detailed information about email marketing legislation across major jurisdictions including GDPR (Europe), CAN-SPAM (USA), CASL (Canada), LGPD (Brazil), and many others.
## What This Resource Provides
The email-marketing-regulations repository is a reference guide that documents:
- **Legal requirements** for email marketing in 20+ countries
- **Consent requirements** (opt-in, opt-out, soft opt-in rules)
- **Content requirements** (sender identification, unsubscribe mechanisms)
- **Penalty structures** for non-compliance
- **Key terminology** (explicit vs implied consent, double opt-in)
- **Regional variations** in data protection laws
This is a documentation resource, not a software library or CLI tool. It's designed for research and compliance planning.
## Installation
Clone the repository to access the documentation locally:
```bash
git clone https://github.com/threeheartsdigital/email-marketing-regulations.git
cd email-marketing-regulations
```
Alternatively, browse the documentation directly on GitHub or reference specific country files as needed.
## Repository Structure
```
email-marketing-regulations/
├── README.md # Overview table of all countries
├── country/
│ ├── australia.md
│ ├── belgium.md
│ ├── brazil.md
│ ├── canada.md
│ ├── china.md
│ ├── denmark.md
│ ├── finland.md
│ ├── germany.md
│ ├── hongkong.md
│ ├── iceland.md
│ ├── india.md
│ ├── ireland.md
│ ├── israel.md
│ ├── japan.md
│ ├── singapore.md
│ ├── south-africa.md
│ ├── uae.md
│ ├── uk.md
│ └── usa.md
```
## Key Regulatory Frameworks
### GDPR (European Union + UK)
**Consent Requirements:**
- Prior explicit consent required for marketing emails
- Soft opt-in exception: existing customers, similar products/services
- Must offer easy opt-out at collection and in every message
**Content Requirements:**
- Clear sender identification
- Valid contact address
- Transparent processing information
**Penalties:**
- Up to €20 million or 4% of annual global turnover (whichever is higher)
- UK: Up to £17.5 million or 4% of annual global turnover
**Example Compliance Checklist:**
```markdown
- [ ] Obtained explicit consent via unticked checkbox
- [ ] Provided clear information about data processing
- [ ] Included unsubscribe link in email footer
- [ ] Sender name and physical address visible
- [ ] Consent records stored with timestamp and method
- [ ] Privacy policy accessible and up-to-date
```
### CAN-SPAM (United States)
**Consent Requirements:**
- No prior consent required (opt-out model)
- Must honor opt-out requests within 10 business days
**Content Requirements:**
- Accurate "From" and "To" information
- Non-deceptive subject lines
- Physical postal address of sender
- Clear identification as advertisement
- Conspicuous opt-out mechanism
**Penalties:**
- Up to $53,088 USD per violation
- Additional penalties for aggravated violations
**Example Compliant Email Footer:**
```html
<footer>
<p><strong>Acme Corporation</strong><br>
123 Main Street, Suite 100<br>
San Francisco, CA 94102<br>
United States</p>
<p>This is a promotional email. If you no longer wish to receive these messages,
<a href="https://example.com/unsubscribe?email={{email}}">click here to unsubscribe</a>.</p>
<p>Questions? Contact us at support@example.com</p>
</footer>
```
### CASL (Canada)
**Consent Requirements:**
- Express consent (written or oral) required by default
- Implied consent for existing business relationships (up to 24 months after transaction)
- Soft opt-in during sales inquiry (6 months)
**Content Requirements:**
- Sender identification (name and contact info)
- Functional unsubscribe mechanism
- Physical mailing address or other contact information
**Penalties:**
- Up to $10 million CAD per violation
**Example Express Consent Form:**
```html
<form action="/subscribe" method="post">
<label for="email">Email Address:</label>
<input type="email" id="email" name="email" required>
<label>
<input type="checkbox" name="consent" value="yes" required>
I consent to receive commercial electronic messages from Acme Corp
about products, services, and special offers. I understand I can
unsubscribe at any time.
</label>
<p><small>We respect your privacy. See our
<a href="/privacy">Privacy Policy</a> for details on how we handle your data.</small></p>
<button type="submit">Subscribe</button>
</form>
```
### LGPD (Brazil)
**Consent Requirements:**
- Consent or documented legitimate interest required
- No statutory soft opt-in provision
- Clear, specific consent statements
**Content Requirements:**
- Transparent sender identification
- Easy opt-out mechanism
- Clear purpose of data processing
**Penalties:**
- Up to 2% of revenue from Brazil
- Maximum 50 million BRL per infraction
**Example Consent Record Structure:**
```json
{
"subscriber_id": "sub_abc123",
"email": "user@example.com.br",
"consent_timestamp": "2026-08-15T14:30:00Z",
"consent_method": "website_signup",
"consent_ip": "203.0.113.42",
"consent_text": "Eu concordo em receber e-mails de marketing da Acme Corp sobre produtos e serviços.",
"legal_basis": "consent",
"purpose": "marketing_communications",
"data_controller": "Acme Corp LTDA",
"opt_out_available": true,
"opt_out_url": "https://example.com.br/cancelar-inscricao"
}
```
## Common Compliance Patterns
### Double Opt-In Implementation
Most stringent jurisdictions benefit from double opt-in:
```javascript
// Example Node.js/Express signup flow
const crypto = require('crypto');
app.post('/api/subscribe', async (req, res) => {
const { email, consentGiven, ipAddress, userAgent } = req.body;
if (!consentGiven) {
return res.status(400).json({ error: 'Consent required' });
}
// Generate confirmation token
const confirmToken = crypto.randomBytes(32).toString('hex');
// Store pending subscription
await db.pendingSubscribers.create({
email,
confirmToken,
consentTimestamp: new Date(),
ipAddress,
userAgent,
status: 'pending_confirmation'
});
// Send confirmation email
await sendEmail({
to: email,
subject: 'Please confirm your subscription',
html: `
<p>Click the link below to confirm your subscription:</p>
<a href="${process.env.BASE_URL}/confirm/${confirmToken}">Confirm Subscription</a>
<p>If you didn't request this, you can safely ignore this email.</p>
`
});
res.json({ success: true, message: 'Confirmation email sent' });
});
app.get('/confirm/:token', async (req, res) => {
const pending = await db.pendingSubscribers.findOne({
confirmToken: req.params.token
});
if (!pending) {
return res.status(404).send('Invalid or expired confirmation link');
}
// Move to confirmed subscribers
await db.subscribers.create({
email: pending.email,
confirmedAt: new Date(),
consentMethod: 'double_opt_in',
sourceIp: pending.ipAddress,
originalConsentTimestamp: pending.consentTimestamp
});
await db.pendingSubscribers.delete({ confirmToken: req.params.token });
res.send('Subscription confirmed! Thank you.');
});
```
### Soft Opt-In Qualification Check
```python
# Example Python function to determine if soft opt-in applies
from datetime import datetime, timedelta
from enum import Enum
class ConsentType(Enum):
EXPLICIT = "explicit"
SOFT_OPT_IN = "soft_opt_in"
NONE = "none"
def check_soft_optin_eligibility(
customer_email: str,
last_purchase_date: datetime,
products_purchased: list[str],
marketing_products: list[str],
gave_optin_at_purchase: bool,
country: str
) -> ConsentType:
"""
Determine if soft opt-in applies based on country regulations.
Note: This is simplified logic. Always consult with legal counsel.
"""
# Soft opt-in generally requires:
# 1. Contact details obtained during a sale
# 2. Marketing for similar products/services
# 3. Easy opt-out provided at collection
# 4. Within time limits (varies by country)
time_limits = {
"GB": timedelta(days=365), # UK: reasonable period
"DE": timedelta(days=365), # Germany: similar products
"IE": timedelta(days=365), # Ireland: 12 months per regulation
"AU": timedelta(days=730), # Australia: reasonable period
"BE": timedelta(days=365), # Belgium: similar to GDPR
}
if country not in time_limits:
return ConsentType.NONE
# Check time limit
time_since_purchase = datetime.now() - last_purchase_date
if time_since_purchase > time_limits[country]:
return ConsentType.NONE
# Check if products are similar
if not any(p in marketing_products for p in products_purchased):
return ConsentType.NONE
# Check if opt-out was offered at purchase
if not gave_optin_at_purchase:
return ConsentType.NONE
return ConsentType.SOFT_OPT_IN
# Usage example
eligibility = check_soft_optin_eligibility(
customer_email="customer@example.com",
last_purchase_date=datetime(2026, 6, 1),
products_purchased=["web_hosting", "domain_registration"],
marketing_products=["ssl_certificates", "email_hosting"],
gave_optin_at_purchase=True,
country="GB"
)
if eligibility == ConsentType.SOFT_OPT_IN:
print("Soft opt-in applies - may send marketing for similar services")
elif eligibility == ConsentType.EXPLICIT:
print("Explicit consent required")
else:
print("No valid consent basis - do not send marketing")
```
### Unsubscribe Management
```ruby
# Example Ruby/Rails unsubscribe handler
class UnsubscribeController < ApplicationController
skip_before_action :verify_authenticity_token, only: [:one_click]
# One-click unsubscribe (RFC 8058 - recommended for compliance)
def one_click
subscriber = Subscriber.find_by(unsubscribe_token: params[:token])
if subscriber
subscriber.update!(
status: 'unsubscribed',
unsubscribed_at: Time.current,
unsubscribe_method: 'one_click',
unsubscribe_ip: request.remote_ip
)
# Log for compliance records
AuditLog.create!(
event: 'unsubscribe',
subscriber_id: subscriber.id,
timestamp: Time.current,
details: { method: 'one_click', ip: request.remote_ip }
)
head :ok
else
head :not_found
end
end
# Web-based unsubscribe page
def show
@subscriber = Subscriber.find_by(unsubscribe_token: params[:token])
unless @subscriber
render :invalid_token and return
end
end
def create
subscriber = Subscriber.find_by(unsubscribe_token: params[:token])
if subscriber
# Honor unsubscribe within 10 business days (CAN-SPAM)
subscriber.update!(
status: 'unsubscribed',
unsubscribed_at: Time.current,
unsubscribe_method: 'web_form',
unsubscribe_reason: params[:reason]
)
# Propagate to all systems immediately
UnsubscribeJob.perform_async(subscriber.email)
redirect_to unsubscribe_confirmed_path
else
render :invalid_token
end
end
end
# Email template with compliant unsubscribe
# app/views/mailers/newsletter.html.erb
# <footer>
# <p>{{ company_name }}<br>
# {{ physical_address }}</p>
#
# <p><a href="<%= unsubscribe_url(token: @subscriber.unsubscribe_token) %>">
# Unsubscribe
# </a> | <a href="<%= preferences_url(token: @subscriber.unsubscribe_token) %>">
# Update Preferences
# </a></p>
# </footer>
```
## Consent Record Keeping
Maintaining detailed consent records is critical for compliance:
```typescript
// TypeScript interface for comprehensive consent records
interface ConsentRecord {
subscriberId: string;
email: string;
// Consent details
consentTimestamp: Date;
consentMethod: 'web_form' | 'api' | 'import' | 'soft_optin' | 'other';
consentType: 'explicit' | 'implied' | 'soft_optin';
consentVersion: string; // Privacy policy version
// Technical details
ipAddress: string;
userAgent: string;
referrerUrl?: string;
// Legal basis
legalBasis: 'consent' | 'legitimate_interest' | 'contract' | 'legal_obligation';
jurisdiction: string; // ISO country code
// Consent text shown to user
consentLanguage: string; // ISO language code
consentText: string;
privacyPolicyUrl: string;
// Scope
purposes: string[]; // e.g., ['newsletter', 'product_updates', 'promotions']
dataCategories: string[]; // e.g., ['email', 'name', 'preferences']
// Lifecycle
confirmed: boolean;
confirmationTimestamp?: Date;
revokedAt?: Date;
revokeMethod?: string;
// Audit trail
lastUpdated: Date;
updatedBy: string;
}
// Example database schema (PostgreSQL)
const createTableSQL = `
CREATE TABLE consent_records (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
subscriber_id VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL,
consent_timestamp TIMESTAMP WITH TIME ZONE NOT NULL,
consent_method VARCHAR(50) NOT NULL,
consent_type VARCHAR(50) NOT NULL,
consent_version VARCHAR(50) NOT NULL,
ip_address INET NOT NULL,
user_agent TEXT,
referrer_url TEXT,
legal_basis VARCHAR(50) NOT NULL,
jurisdiction VARCHAR(2) NOT NULL,
GitHub에서 보기