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"]
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
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:
- [ ] 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:
<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,
<ahref="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:
<formaction="/subscribe"method="post"><labelfor="email">Email Address:</label><inputtype="email"id="email"name="email"required><label><inputtype="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
<ahref="/privacy">Privacy Policy</a> for details on how we handle your data.</small></p><buttontype="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:
{"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:
// Example Node.js/Express signup flowconst 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 tokenconst confirmToken = crypto.randomBytes(32).toString('hex');
// Store pending subscriptionawait db.pendingSubscribers.create({
email,
confirmToken,
consentTimestamp: newDate(),
ipAddress,
userAgent,
status: 'pending_confirmation'
});
// Send confirmation emailawaitsendEmail({
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 subscribersawait db.subscribers.create({
email: pending.email,
confirmedAt: newDate(),
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
# Example Python function to determine if soft opt-in appliesfrom datetime import datetime, timedelta
from enum import Enum
classConsentType(Enum):
EXPLICIT = "explicit"
SOFT_OPT_IN = "soft_opt_in"
NONE = "none"defcheck_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 notin 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 similarifnotany(p in marketing_products for p in products_purchased):
return ConsentType.NONE
# Check if opt-out was offered at purchaseifnot 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
# Example Ruby/Rails unsubscribe handlerclassUnsubscribeController < ApplicationController
skip_before_action :verify_authenticity_token, only: [:one_click]
# One-click unsubscribe (RFC 8058 - recommended for compliance)defone_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 recordsAuditLog.create!(
event:'unsubscribe',
subscriber_id: subscriber.id,
timestamp:Time.current,
details: { method:'one_click', ip: request.remote_ip }
)
head :okelse
head :not_foundendend# Web-based unsubscribe pagedefshow@subscriber = Subscriber.find_by(unsubscribe_token: params[:token])
unless@subscriber
render :invalid_tokenandreturnendenddefcreate
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 immediatelyUnsubscribeJob.perform_async(subscriber.email)
redirect_to unsubscribe_confirmed_path
else
render :invalid_tokenendendend# 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 interface for comprehensive consent recordsinterfaceConsentRecord {
subscriberId: string;
email: string;
// Consent detailsconsentTimestamp: Date;
consentMethod: 'web_form' | 'api' | 'import' | 'soft_optin' | 'other';
consentType: 'explicit' | 'implied' | 'soft_optin';
consentVersion: string; // Privacy policy version// Technical detailsipAddress: string;
userAgent: string;
referrerUrl?: string;
// Legal basislegalBasis: 'consent' | 'legitimate_interest' | 'contract' | 'legal_obligation';
jurisdiction: string; // ISO country code// Consent text shown to userconsentLanguage: string; // ISO language codeconsentText: string;
privacyPolicyUrl: string;
// Scopepurposes: string[]; // e.g., ['newsletter', 'product_updates', 'promotions']dataCategories: string[]; // e.g., ['email', 'name', 'preferences']// Lifecycleconfirmed: boolean;
confirmationTimestamp?: Date;
revokedAt?: Date;
revokeMethod?: string;
// Audit traillastUpdated: 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,
consent_language VARCHAR(5) NOT NULL,
consent_text TEXT NOT NULL,
privacy_policy_url TEXT NOT NULL,
purposes JSONB NOT NULL,
data_categories JSONB NOT NULL,
confirmed BOOLEAN DEFAULT FALSE,
confirmation_timestamp TIMESTAMP WITH TIME ZONE,
revoked_at TIMESTAMP WITH TIME ZONE,
revoke_method VARCHAR(50),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_by VARCHAR(255),
INDEX idx_subscriber_id (subscriber_id),
INDEX idx_email (email),
INDEX idx_consent_timestamp (consent_timestamp),
INDEX idx_jurisdiction (jurisdiction)
);
`;
Multi-Jurisdiction Compliance Strategy
# Example compliance configuration file# compliance-config.ymljurisdictions:EU:legislation:GDPRconsent_required:explicitsoft_optin_allowed:truesoft_optin_conditions:-existing_customer-similar_products-opt_out_offeredcontent_requirements:-sender_identification-contact_address-unsubscribe_linkretention_limits:marketing_consent:2_yearsconsent_records:6_yearspenalties:max_fine:"€20M or 4% global turnover"US:legislation:CAN-SPAMconsent_required:falseopt_out_model:truecontent_requirements:-accurate_header-truthful_subject-physical_address-clear_advertisement-conspicuous_unsubscribeopt_out_processing_days:10penalties:per_violation:"$53,088 USD"CA:legislation:CASLconsent_required:expressimplied_consent_duration:business_relationship:24_monthsinquiry:6_monthscontent_requirements:-sender_identification-contact_info-unsubscribe_mechanismpenalties:max_fine:"$10M CAD"BR:legislation:LGPDconsent_required:truesoft_optin_allowed:falselegal_bases:-consent-legitimate_interestcontent_requirements:-transparent_sender-opt_out_mechanismpenalties:max_fine:"2% revenue (Brazil), up to 50M BRL"# Usage in applicationdefget_compliance_rules(country_code)jurisdiction=map_country_to_jurisdiction(country_code)COMPLIANCE_CONFIG['jurisdictions'][jurisdiction]end
Quick Reference Checklist
Use this checklist when setting up email marketing campaigns:
## Pre-Campaign Compliance Checklist### Consent & Legal Basis- [ ] Identified target jurisdictions
- [ ] Determined applicable laws (GDPR, CAN-SPAM, CASL, etc.)
- [ ] Obtained appropriate consent type (explicit/implied/soft opt-in)
- [ ] Documented consent records with timestamps
- [ ] Verified soft opt-in eligibility if applicable
### Content Requirements- [ ] Sender clearly identified (no misleading "From" names)
- [ ] Physical mailing address included in footer
- [ ] Subject line is truthful and not deceptive
- [ ] Email marked as advertisement if required by jurisdiction
- [ ] Privacy policy linked and accessible
### Unsubscribe Mechanism- [ ] Unsubscribe link present and conspicuous
- [ ] Unsubscribe process free of charge
- [ ] Unsubscribe process requires minimal steps (one-click preferred)
- [ ] System processes unsubscribes within required timeframe
- [ ] Preference center available (optional but recommended)
### Data Protection- [ ] Data minimization applied (collect only necessary data)
- [ ] Secure storage of personal data and consent records
- [ ] Data retention policies in place
- [ ] Data processing agreement with ESP if applicable
- [ ] Cross-border data transfer mechanisms compliant
### Testing & Monitoring- [ ] Test email renders correctly
- [ ] All links functional (especially unsubscribe)
- [ ] Suppression list applied to remove unsubscribed users
- [ ] Bounce handling configured
- [ ] Complaint monitoring active
Country-Specific Resources
To access detailed information for a specific country, reference the individual country files:
# View regulations for a specific countrycat country/canada.md
cat country/germany.md
cat country/australia.md
# Search for specific terms across all countries
grep -r "soft opt-in" country/
grep -r "double opt-in" country/
# Find penalty information
grep -r "Penalties" country/ -A 5
Integration with Email Service Providers
Most ESPs provide compliance features. Here's how to verify your setup:
Problem: Unsure which regulations govern your email marketing.
Solution:
Identify where you are located (sender jurisdiction)
Identify where your recipients are located (recipient jurisdiction)
Identify where email is processed (server location)
Apply the most stringent applicable law
Reference the README.md table to see requirements at a glance, then review specific country files.
Issue: Soft Opt-In vs. Explicit Consent
Problem: Confusion about when soft opt-in can be used.
Solution:
Soft opt-in is an exception, not a default
Only applies when ALL conditions are met:
Contact details obtained during a sale/inquiry
Marketing is for YOUR OWN similar products
Opt-out was offered when collecting details
Opt-out is in every message
Within time limits (varies by country)
When in doubt, use explicit consent (safer)
Issue: International Audience
Problem: Subscribers across multiple jurisdictions.
Solution:
# Segment lists by jurisdiction and apply appropriate rulesdefsegment_by_compliance_region(subscribers):
regions = {
'GDPR': [], # EU + EEA'CASL': [], # Canada'CAN_SPAM': [], # United States'LGPD': [], # Brazil'OTHER': []
}
for subscriber in subscribers:
country = subscriber.country_code
if country in ['AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE',
'FI', 'FR', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV',
'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK',
'SI', 'ES', 'SE', 'IS', 'LI', 'NO']:
regions['GDPR'].append(subscriber)
elif country == 'CA':
regions['CASL'].append(subscriber)
elif country == 'US':
regions['CAN_SPAM'].append(subscriber)
elif country == 'BR':
regions['LGPD'].append(subscriber)
else:
regions['OTHER'].append(subscriber)
return regions
# Apply strictest standard globally for simplicity# (Many companies default to GDPR compliance worldwide)
Issue: Consent Records Missing
Problem: Historic subscribers without documented consent.
Solution:
Do not retroactively claim consent
Send re-permission campaign to reconfirm interest
Remove non-responders after reasonable period
Implement proper consent tracking going forward
<!-- Re-permission email template --><h2>We Value Your Privacy</h2><p>We're updating our systems to ensure we have your explicit permission
to send you marketing emails. We'd love to stay in touch!</p><p>Please confirm you'd like to continue receiving our newsletter:</p><ahref="{{reconfirm_url}}"style="background: #007bff; color: white;
padding: 10px 20px; text-decoration: none; display: inline-block;">
Yes, Keep Me Subscribed
</a><p><small>If you don't confirm by {{deadline_date}}, you'll be
automatically unsubscribed. You can always resubscribe later
at {{signup_url}}.</small></p>
Legal Disclaimer
This skill provides general information about email marketing regulations based on the open-source repository maintained by EmailOctopus and contributors. It is not legal advice.
Laws change frequently
Information may be incomplete or outdated
Interpretation varies by jurisdiction
Every situation is unique
Always consult with a qualified attorney in the relevant jurisdiction before conducting email marketing campaigns. The repository maintainers, contributors, and this skill author accept no liability for decisions made based on this information.