first commit
This commit is contained in:
9
.env.example
Normal file
9
.env.example
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# SMTP2GO API Configuration
|
||||||
|
SMTP2GO_API_KEY=your-api-key-here
|
||||||
|
|
||||||
|
# Sender Configuration
|
||||||
|
SENDER_EMAIL=security@yourdomain.com
|
||||||
|
SENDER_NAME=IT Security Team
|
||||||
|
|
||||||
|
# Company name used in templates
|
||||||
|
COMPANY_NAME=Your Company Name
|
||||||
73
.gitignore
vendored
Normal file
73
.gitignore
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# Python
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
*.egg-info/
|
||||||
|
.eggs/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
.dev.vars
|
||||||
|
|
||||||
|
# Cloudflare Wrangler
|
||||||
|
.wrangler/
|
||||||
|
.dev.sqlite
|
||||||
|
.mf/
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
dist/
|
||||||
|
out/
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Test coverage
|
||||||
|
coverage/
|
||||||
|
.nyc_output/
|
||||||
|
.pytest_cache/
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
*.tar
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
*.tmp
|
||||||
52
CLAUDE.md
Normal file
52
CLAUDE.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Purpose
|
||||||
|
|
||||||
|
Phishtest is a phishing email testing tool for evaluating Proofpoint TAP (Targeted Attack Protection) systems. It sends test phishing emails via SMTP2GO API to assess email security controls.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Activate virtual environment
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Run CLI commands
|
||||||
|
python -m src.main list-templates
|
||||||
|
python -m src.main preview --template <name>
|
||||||
|
python -m src.main send --template <name> --to <email>
|
||||||
|
python -m src.main send --template <name> --csv <file.csv>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── main.py # Click CLI - entry point, command definitions
|
||||||
|
├── config.py # Environment config loading via python-dotenv
|
||||||
|
├── template_loader.py # Jinja2 template loading/rendering from templates/
|
||||||
|
├── csv_loader.py # CSV recipient parsing with email validation
|
||||||
|
└── email_sender.py # SMTP2GO API wrapper using smtp2go library
|
||||||
|
```
|
||||||
|
|
||||||
|
**Data flow:** CLI → loads config → loads template → loads recipients → renders template per recipient → sends via smtp2go
|
||||||
|
|
||||||
|
## Template System
|
||||||
|
|
||||||
|
Templates live in `templates/<name>/` with:
|
||||||
|
- `metadata.json` - subject, sender_name
|
||||||
|
- `template.html` - Jinja2 HTML body
|
||||||
|
- `template.txt` - Jinja2 plain text body
|
||||||
|
|
||||||
|
Variables: `{{recipient_name}}`, `{{recipient_email}}`, `{{company_name}}`, `{{date}}`
|
||||||
|
|
||||||
|
## Key Dependencies
|
||||||
|
|
||||||
|
- `smtp2go` - Official SMTP2GO Python library for email sending
|
||||||
|
- `click` - CLI framework
|
||||||
|
- `jinja2` - Template rendering
|
||||||
|
- `python-dotenv` - Environment variable loading
|
||||||
93
README.md
Normal file
93
README.md
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
# Phishtest
|
||||||
|
|
||||||
|
A phishing email testing tool designed to test Proofpoint TAP (Targeted Attack Protection) systems. Sends test phishing emails via SMTP2GO.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Create and activate virtual environment:
|
||||||
|
```bash
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install dependencies:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Configure environment:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env with your SMTP2GO API key and sender settings
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### List available templates
|
||||||
|
```bash
|
||||||
|
python -m src.main list-templates
|
||||||
|
```
|
||||||
|
|
||||||
|
### Preview a template
|
||||||
|
```bash
|
||||||
|
python -m src.main preview --template password-reset --name "John Doe" --email "john@example.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Send to a single recipient
|
||||||
|
```bash
|
||||||
|
python -m src.main send --template password-reset --to user@example.com --name "Test User"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Send to multiple recipients from CSV
|
||||||
|
```bash
|
||||||
|
python -m src.main send --template password-reset --csv recipients.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dry run (preview without sending)
|
||||||
|
```bash
|
||||||
|
python -m src.main send --template password-reset --csv recipients.csv --dry-run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating Templates
|
||||||
|
|
||||||
|
Templates are stored in `templates/<template-name>/` with three files:
|
||||||
|
|
||||||
|
- `metadata.json` - Subject line and sender name
|
||||||
|
- `template.html` - HTML email body
|
||||||
|
- `template.txt` - Plain text email body
|
||||||
|
|
||||||
|
### Available template variables
|
||||||
|
|
||||||
|
- `{{recipient_name}}` - Recipient's name
|
||||||
|
- `{{recipient_email}}` - Recipient's email address
|
||||||
|
- `{{company_name}}` - Company name from config
|
||||||
|
- `{{date}}` - Current date
|
||||||
|
|
||||||
|
### Example metadata.json
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"subject": "Password Reset Required",
|
||||||
|
"sender_name": "IT Security Team"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## CSV Format
|
||||||
|
|
||||||
|
Recipients CSV must have an `email` column. The `name` column is optional.
|
||||||
|
|
||||||
|
```csv
|
||||||
|
email,name
|
||||||
|
john.doe@example.com,John Doe
|
||||||
|
jane.smith@example.com,Jane Smith
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Set these in `.env` or as environment variables:
|
||||||
|
|
||||||
|
| Variable | Required | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| SMTP2GO_API_KEY | Yes | Your SMTP2GO API key |
|
||||||
|
| SENDER_EMAIL | Yes | Sender email address (must be verified in SMTP2GO) |
|
||||||
|
| SENDER_NAME | No | Default sender display name |
|
||||||
|
| COMPANY_NAME | No | Company name for templates |
|
||||||
2
recipients.csv
Normal file
2
recipients.csv
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
email,name
|
||||||
|
ptarrant@gmail.com,Phillip Tarrant
|
||||||
|
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
smtp2go>=1.0.0
|
||||||
|
python-dotenv>=1.0.0
|
||||||
|
jinja2>=3.1.0
|
||||||
|
click>=8.1.0
|
||||||
1
src/__init__.py
Normal file
1
src/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# Phishtest - Phishing Test System for Proofpoint TAP Testing
|
||||||
27
src/config.py
Normal file
27
src/config.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
"""Configuration management for phishtest."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
|
||||||
|
# Load .env file from project root
|
||||||
|
PROJECT_ROOT = Path(__file__).parent.parent
|
||||||
|
load_dotenv(PROJECT_ROOT / ".env")
|
||||||
|
|
||||||
|
|
||||||
|
def get_config() -> dict:
|
||||||
|
"""Get configuration from environment variables."""
|
||||||
|
return {
|
||||||
|
"smtp2go_api_key": os.getenv("SMTP2GO_API_KEY"),
|
||||||
|
"sender_email": os.getenv("SENDER_EMAIL"),
|
||||||
|
"sender_name": os.getenv("SENDER_NAME", "Phishing Test"),
|
||||||
|
"company_name": os.getenv("COMPANY_NAME", "Your Company"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def validate_config(config: dict) -> list[str]:
|
||||||
|
"""Validate required configuration values. Returns list of missing keys."""
|
||||||
|
required = ["smtp2go_api_key", "sender_email"]
|
||||||
|
missing = [key for key in required if not config.get(key)]
|
||||||
|
return missing
|
||||||
77
src/csv_loader.py
Normal file
77
src/csv_loader.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
"""CSV file loading for recipient lists."""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
EMAIL_REGEX = re.compile(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$")
|
||||||
|
|
||||||
|
|
||||||
|
class Recipient:
|
||||||
|
"""Represents an email recipient."""
|
||||||
|
|
||||||
|
def __init__(self, email: str, name: str = ""):
|
||||||
|
self.email = email
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"recipient_email": self.email,
|
||||||
|
"recipient_name": self.name or self.email.split("@")[0],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def validate_email(email: str) -> bool:
|
||||||
|
"""Validate email format."""
|
||||||
|
return bool(EMAIL_REGEX.match(email))
|
||||||
|
|
||||||
|
|
||||||
|
def load_recipients_from_csv(csv_path: str | Path) -> list[Recipient]:
|
||||||
|
"""
|
||||||
|
Load recipients from a CSV file.
|
||||||
|
|
||||||
|
Expected columns: email (required), name (optional)
|
||||||
|
Returns list of Recipient objects.
|
||||||
|
"""
|
||||||
|
csv_path = Path(csv_path)
|
||||||
|
|
||||||
|
if not csv_path.exists():
|
||||||
|
raise FileNotFoundError(f"CSV file not found: {csv_path}")
|
||||||
|
|
||||||
|
recipients = []
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
with open(csv_path, newline="", encoding="utf-8") as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
|
||||||
|
# Check for required column
|
||||||
|
if "email" not in (reader.fieldnames or []):
|
||||||
|
raise ValueError("CSV file must have an 'email' column")
|
||||||
|
|
||||||
|
for row_num, row in enumerate(reader, start=2): # start=2 accounts for header
|
||||||
|
email = row.get("email", "").strip()
|
||||||
|
name = row.get("name", "").strip()
|
||||||
|
|
||||||
|
if not email:
|
||||||
|
errors.append(f"Row {row_num}: empty email")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not validate_email(email):
|
||||||
|
errors.append(f"Row {row_num}: invalid email format '{email}'")
|
||||||
|
continue
|
||||||
|
|
||||||
|
recipients.append(Recipient(email=email, name=name))
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
error_msg = "\n".join(errors)
|
||||||
|
raise ValueError(f"CSV validation errors:\n{error_msg}")
|
||||||
|
|
||||||
|
return recipients
|
||||||
|
|
||||||
|
|
||||||
|
def create_recipient(email: str, name: str = "") -> Recipient:
|
||||||
|
"""Create a single recipient, validating the email."""
|
||||||
|
if not validate_email(email):
|
||||||
|
raise ValueError(f"Invalid email format: {email}")
|
||||||
|
return Recipient(email=email, name=name)
|
||||||
103
src/email_sender.py
Normal file
103
src/email_sender.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
"""Email sending via smtp2go API."""
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
from smtp2go.core import Smtp2goClient
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SendResult:
|
||||||
|
"""Result of sending an email."""
|
||||||
|
|
||||||
|
recipient: str
|
||||||
|
success: bool
|
||||||
|
error: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class EmailSender:
|
||||||
|
"""Sends emails via smtp2go API."""
|
||||||
|
|
||||||
|
def __init__(self, api_key: str):
|
||||||
|
self.client = Smtp2goClient(api_key=api_key)
|
||||||
|
|
||||||
|
def send_email(
|
||||||
|
self,
|
||||||
|
sender_email: str,
|
||||||
|
sender_name: str,
|
||||||
|
recipient_email: str,
|
||||||
|
subject: str,
|
||||||
|
html_body: str = "",
|
||||||
|
text_body: str = "",
|
||||||
|
) -> SendResult:
|
||||||
|
"""Send a single email."""
|
||||||
|
# Format sender with display name
|
||||||
|
sender = f"{sender_name} <{sender_email}>" if sender_name else sender_email
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"sender": sender,
|
||||||
|
"recipients": [recipient_email],
|
||||||
|
"subject": subject,
|
||||||
|
}
|
||||||
|
|
||||||
|
if html_body:
|
||||||
|
payload["html"] = html_body
|
||||||
|
if text_body:
|
||||||
|
payload["text"] = text_body
|
||||||
|
|
||||||
|
# Must have at least one body
|
||||||
|
if not html_body and not text_body:
|
||||||
|
return SendResult(
|
||||||
|
recipient=recipient_email,
|
||||||
|
success=False,
|
||||||
|
error="Email must have HTML or text body",
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = self.client.send(**payload)
|
||||||
|
|
||||||
|
if response.success:
|
||||||
|
return SendResult(recipient=recipient_email, success=True)
|
||||||
|
else:
|
||||||
|
error_msg = ", ".join(response.errors) if response.errors else "Unknown error"
|
||||||
|
return SendResult(
|
||||||
|
recipient=recipient_email, success=False, error=error_msg
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return SendResult(recipient=recipient_email, success=False, error=str(e))
|
||||||
|
|
||||||
|
def send_batch(
|
||||||
|
self,
|
||||||
|
sender_email: str,
|
||||||
|
sender_name: str,
|
||||||
|
recipients: list[dict],
|
||||||
|
template_renderer: callable,
|
||||||
|
) -> list[SendResult]:
|
||||||
|
"""
|
||||||
|
Send emails to multiple recipients.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sender_email: Sender email address
|
||||||
|
sender_name: Sender display name
|
||||||
|
recipients: List of recipient dicts with keys like 'recipient_email', 'recipient_name'
|
||||||
|
template_renderer: Function that takes recipient dict and returns (subject, html, text)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of SendResult objects
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
|
||||||
|
for recipient in recipients:
|
||||||
|
subject, html_body, text_body = template_renderer(recipient)
|
||||||
|
|
||||||
|
result = self.send_email(
|
||||||
|
sender_email=sender_email,
|
||||||
|
sender_name=sender_name,
|
||||||
|
recipient_email=recipient["recipient_email"],
|
||||||
|
subject=subject,
|
||||||
|
html_body=html_body,
|
||||||
|
text_body=text_body,
|
||||||
|
)
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
|
return results
|
||||||
171
src/main.py
Normal file
171
src/main.py
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
"""CLI interface for phishtest."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from .config import get_config, validate_config
|
||||||
|
from .csv_loader import create_recipient, load_recipients_from_csv
|
||||||
|
from .email_sender import EmailSender
|
||||||
|
from .template_loader import list_templates, load_template, render_template
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def cli():
|
||||||
|
"""Phishtest - Phishing email testing tool for Proofpoint TAP."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command("list-templates")
|
||||||
|
def list_templates_cmd():
|
||||||
|
"""List all available email templates."""
|
||||||
|
templates = list_templates()
|
||||||
|
|
||||||
|
if not templates:
|
||||||
|
click.echo("No templates found in templates/ directory.")
|
||||||
|
click.echo("Create a template folder with metadata.json, template.html, and template.txt")
|
||||||
|
return
|
||||||
|
|
||||||
|
click.echo("Available templates:")
|
||||||
|
for name in templates:
|
||||||
|
try:
|
||||||
|
template = load_template(name)
|
||||||
|
click.echo(f" - {name}: {template.subject}")
|
||||||
|
except Exception as e:
|
||||||
|
click.echo(f" - {name}: (error loading: {e})")
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command("preview")
|
||||||
|
@click.option("--template", "-t", required=True, help="Template name to preview")
|
||||||
|
@click.option("--name", "-n", default="Test User", help="Recipient name for preview")
|
||||||
|
@click.option("--email", "-e", default="test@example.com", help="Recipient email for preview")
|
||||||
|
def preview_cmd(template: str, name: str, email: str):
|
||||||
|
"""Preview a template with sample data."""
|
||||||
|
config = get_config()
|
||||||
|
|
||||||
|
try:
|
||||||
|
tmpl = load_template(template)
|
||||||
|
except ValueError as e:
|
||||||
|
click.echo(f"Error: {e}", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
variables = {
|
||||||
|
"recipient_name": name,
|
||||||
|
"recipient_email": email,
|
||||||
|
"company_name": config["company_name"],
|
||||||
|
}
|
||||||
|
|
||||||
|
subject, html_body, text_body = render_template(tmpl, variables)
|
||||||
|
|
||||||
|
click.echo("=" * 60)
|
||||||
|
click.echo(f"Subject: {subject}")
|
||||||
|
click.echo("=" * 60)
|
||||||
|
|
||||||
|
if html_body:
|
||||||
|
click.echo("\n--- HTML Body ---")
|
||||||
|
click.echo(html_body)
|
||||||
|
|
||||||
|
if text_body:
|
||||||
|
click.echo("\n--- Text Body ---")
|
||||||
|
click.echo(text_body)
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command("send")
|
||||||
|
@click.option("--template", "-t", required=True, help="Template name to use")
|
||||||
|
@click.option("--to", "recipient_email", help="Single recipient email address")
|
||||||
|
@click.option("--csv", "csv_file", type=click.Path(exists=True), help="CSV file with recipients")
|
||||||
|
@click.option("--name", "-n", default="", help="Recipient name (for single recipient)")
|
||||||
|
@click.option("--dry-run", is_flag=True, help="Preview without sending")
|
||||||
|
def send_cmd(template: str, recipient_email: str, csv_file: str, name: str, dry_run: bool):
|
||||||
|
"""Send phishing test emails."""
|
||||||
|
# Validate we have either --to or --csv
|
||||||
|
if not recipient_email and not csv_file:
|
||||||
|
click.echo("Error: Must specify either --to or --csv", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if recipient_email and csv_file:
|
||||||
|
click.echo("Error: Cannot specify both --to and --csv", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Validate config
|
||||||
|
config = get_config()
|
||||||
|
missing = validate_config(config)
|
||||||
|
if missing:
|
||||||
|
click.echo(f"Error: Missing required config: {', '.join(missing)}", err=True)
|
||||||
|
click.echo("Set these in .env file or as environment variables.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Load template
|
||||||
|
try:
|
||||||
|
tmpl = load_template(template)
|
||||||
|
except ValueError as e:
|
||||||
|
click.echo(f"Error: {e}", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Load recipients
|
||||||
|
recipients = []
|
||||||
|
try:
|
||||||
|
if recipient_email:
|
||||||
|
recipient = create_recipient(recipient_email, name)
|
||||||
|
recipients = [recipient]
|
||||||
|
else:
|
||||||
|
recipients = load_recipients_from_csv(csv_file)
|
||||||
|
except (ValueError, FileNotFoundError) as e:
|
||||||
|
click.echo(f"Error: {e}", err=True)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if not recipients:
|
||||||
|
click.echo("No recipients to send to.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
click.echo(f"Template: {template}")
|
||||||
|
click.echo(f"Recipients: {len(recipients)}")
|
||||||
|
click.echo(f"Sender: {config['sender_name']} <{config['sender_email']}>")
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
click.echo("\n[DRY RUN] Would send to:")
|
||||||
|
for r in recipients:
|
||||||
|
click.echo(f" - {r.name} <{r.email}>" if r.name else f" - {r.email}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Confirm before sending
|
||||||
|
if not click.confirm("\nProceed with sending?"):
|
||||||
|
click.echo("Aborted.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Send emails
|
||||||
|
sender = EmailSender(api_key=config["smtp2go_api_key"])
|
||||||
|
|
||||||
|
# Get sender name from template or config
|
||||||
|
sender_name = tmpl.sender_name or config["sender_name"]
|
||||||
|
|
||||||
|
def render_for_recipient(recipient_dict: dict) -> tuple[str, str, str]:
|
||||||
|
variables = {
|
||||||
|
**recipient_dict,
|
||||||
|
"company_name": config["company_name"],
|
||||||
|
}
|
||||||
|
return render_template(tmpl, variables)
|
||||||
|
|
||||||
|
recipient_dicts = [r.to_dict() for r in recipients]
|
||||||
|
results = sender.send_batch(
|
||||||
|
sender_email=config["sender_email"],
|
||||||
|
sender_name=sender_name,
|
||||||
|
recipients=recipient_dicts,
|
||||||
|
template_renderer=render_for_recipient,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Report results
|
||||||
|
success_count = sum(1 for r in results if r.success)
|
||||||
|
fail_count = len(results) - success_count
|
||||||
|
|
||||||
|
click.echo(f"\nResults: {success_count} sent, {fail_count} failed")
|
||||||
|
|
||||||
|
for result in results:
|
||||||
|
if result.success:
|
||||||
|
click.echo(f" [OK] {result.recipient}")
|
||||||
|
else:
|
||||||
|
click.echo(f" [FAIL] {result.recipient}: {result.error}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
cli()
|
||||||
111
src/template_loader.py
Normal file
111
src/template_loader.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
"""Template loading and rendering for phishing emails."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from jinja2 import Environment, FileSystemLoader, select_autoescape
|
||||||
|
|
||||||
|
|
||||||
|
PROJECT_ROOT = Path(__file__).parent.parent
|
||||||
|
TEMPLATES_DIR = PROJECT_ROOT / "templates"
|
||||||
|
|
||||||
|
|
||||||
|
class Template:
|
||||||
|
"""Represents a phishing email template."""
|
||||||
|
|
||||||
|
def __init__(self, name: str, metadata: dict, html_content: str, text_content: str):
|
||||||
|
self.name = name
|
||||||
|
self.metadata = metadata
|
||||||
|
self.html_content = html_content
|
||||||
|
self.text_content = text_content
|
||||||
|
|
||||||
|
@property
|
||||||
|
def subject(self) -> str:
|
||||||
|
return self.metadata.get("subject", "No Subject")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sender_name(self) -> str | None:
|
||||||
|
return self.metadata.get("sender_name")
|
||||||
|
|
||||||
|
|
||||||
|
def list_templates() -> list[str]:
|
||||||
|
"""List all available template names."""
|
||||||
|
if not TEMPLATES_DIR.exists():
|
||||||
|
return []
|
||||||
|
|
||||||
|
templates = []
|
||||||
|
for path in TEMPLATES_DIR.iterdir():
|
||||||
|
if path.is_dir() and (path / "metadata.json").exists():
|
||||||
|
templates.append(path.name)
|
||||||
|
|
||||||
|
return sorted(templates)
|
||||||
|
|
||||||
|
|
||||||
|
def load_template(name: str) -> Template:
|
||||||
|
"""Load a template by name."""
|
||||||
|
template_dir = TEMPLATES_DIR / name
|
||||||
|
|
||||||
|
if not template_dir.exists():
|
||||||
|
raise ValueError(f"Template '{name}' not found in {TEMPLATES_DIR}")
|
||||||
|
|
||||||
|
# Load metadata
|
||||||
|
metadata_path = template_dir / "metadata.json"
|
||||||
|
if not metadata_path.exists():
|
||||||
|
raise ValueError(f"Template '{name}' missing metadata.json")
|
||||||
|
|
||||||
|
with open(metadata_path) as f:
|
||||||
|
metadata = json.load(f)
|
||||||
|
|
||||||
|
# Load HTML template
|
||||||
|
html_path = template_dir / "template.html"
|
||||||
|
html_content = ""
|
||||||
|
if html_path.exists():
|
||||||
|
html_content = html_path.read_text()
|
||||||
|
|
||||||
|
# Load text template
|
||||||
|
text_path = template_dir / "template.txt"
|
||||||
|
text_content = ""
|
||||||
|
if text_path.exists():
|
||||||
|
text_content = text_path.read_text()
|
||||||
|
|
||||||
|
if not html_content and not text_content:
|
||||||
|
raise ValueError(f"Template '{name}' has no template.html or template.txt")
|
||||||
|
|
||||||
|
return Template(name, metadata, html_content, text_content)
|
||||||
|
|
||||||
|
|
||||||
|
def render_template(template: Template, variables: dict) -> tuple[str, str, str]:
|
||||||
|
"""
|
||||||
|
Render a template with the given variables.
|
||||||
|
|
||||||
|
Returns: (subject, html_body, text_body)
|
||||||
|
"""
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader(TEMPLATES_DIR / template.name),
|
||||||
|
autoescape=select_autoescape(['html'])
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add current date to variables
|
||||||
|
render_vars = {
|
||||||
|
"date": datetime.now().strftime("%B %d, %Y"),
|
||||||
|
**variables
|
||||||
|
}
|
||||||
|
|
||||||
|
# Render subject
|
||||||
|
subject_template = env.from_string(template.subject)
|
||||||
|
subject = subject_template.render(**render_vars)
|
||||||
|
|
||||||
|
# Render HTML body
|
||||||
|
html_body = ""
|
||||||
|
if template.html_content:
|
||||||
|
html_template = env.from_string(template.html_content)
|
||||||
|
html_body = html_template.render(**render_vars)
|
||||||
|
|
||||||
|
# Render text body
|
||||||
|
text_body = ""
|
||||||
|
if template.text_content:
|
||||||
|
text_template = env.from_string(template.text_content)
|
||||||
|
text_body = text_template.render(**render_vars)
|
||||||
|
|
||||||
|
return subject, html_body, text_body
|
||||||
4
templates/docusign/metadata.json
Normal file
4
templates/docusign/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "Please DocuSign: {{ company_name }} - Agreement Document",
|
||||||
|
"sender_name": "DocuSign"
|
||||||
|
}
|
||||||
210
templates/docusign/template.html
Normal file
210
templates/docusign/template.html
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px 30px;
|
||||||
|
border-bottom: 4px solid #ffc829;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.document-icon {
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.document-icon img {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
.doc-placeholder {
|
||||||
|
width: 80px;
|
||||||
|
height: 100px;
|
||||||
|
background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%);
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 0 auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.doc-placeholder::after {
|
||||||
|
content: "PDF";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
font-size: 12px;
|
||||||
|
color: #c00;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.doc-placeholder::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 0 20px 20px 0;
|
||||||
|
border-color: transparent #ddd transparent transparent;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0 10px;
|
||||||
|
}
|
||||||
|
.sender-info {
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
.sender-info strong {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 25px 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #ffc829;
|
||||||
|
color: #333 !important;
|
||||||
|
padding: 14px 40px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.button:hover {
|
||||||
|
background-color: #e6b625;
|
||||||
|
}
|
||||||
|
.details {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.details-row {
|
||||||
|
display: flex;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
.details-label {
|
||||||
|
color: #666;
|
||||||
|
width: 120px;
|
||||||
|
}
|
||||||
|
.details-value {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.message-box {
|
||||||
|
background-color: #f0f7ff;
|
||||||
|
border-left: 4px solid #0077cc;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding: 20px 30px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #666;
|
||||||
|
border-top: 1px solid #e5e5e5;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #0077cc;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.security-notice {
|
||||||
|
margin-top: 15px;
|
||||||
|
padding-top: 15px;
|
||||||
|
border-top: 1px solid #e5e5e5;
|
||||||
|
}
|
||||||
|
.alternate-link {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
.alternate-link a {
|
||||||
|
color: #0077cc;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<img src="https://www.docusign.com/sites/default/files/docusign_logo_black_text_on_white_0.png" alt="DocuSign" class="logo" />
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="document-icon">
|
||||||
|
<div class="doc-placeholder"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="title">Please review and sign this document</div>
|
||||||
|
|
||||||
|
<div class="sender-info">
|
||||||
|
<strong>HR Department</strong> sent you a document to review and sign.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="message-box">
|
||||||
|
<strong>Message from HR Department:</strong><br>
|
||||||
|
Hi {{ recipient_name }}, please review and sign the attached agreement at your earliest convenience. This document requires your signature by {{ date }}.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="details">
|
||||||
|
<div class="details-row">
|
||||||
|
<span class="details-label">Document:</span>
|
||||||
|
<span class="details-value">{{ company_name }} - Employment Agreement.pdf</span>
|
||||||
|
</div>
|
||||||
|
<div class="details-row">
|
||||||
|
<span class="details-label">Sender:</span>
|
||||||
|
<span class="details-value">hr@{{ company_name | lower | replace(" ", "") }}.com</span>
|
||||||
|
</div>
|
||||||
|
<div class="details-row">
|
||||||
|
<span class="details-label">Sent:</span>
|
||||||
|
<span class="details-value">{{ date }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="https://rewirespace.com/docusign?email={{ recipient_email }}" class="button">Review Document</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alternate-link">
|
||||||
|
<a href="https://rewirespace.com/docusign?email={{ recipient_email }}">Alternate signing method</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p><strong>Do Not Share This Email</strong></p>
|
||||||
|
<p>This email contains a secure link to DocuSign. Please do not share this email, link, or access code with others.</p>
|
||||||
|
|
||||||
|
<div class="security-notice">
|
||||||
|
<p><strong>About DocuSign</strong></p>
|
||||||
|
<p>Sign documents electronically in just minutes. It's safe, secure, and legally binding. Whether you're in an office, at home, on-the-go or even across the globe, DocuSign provides a professional trusted solution for digital transaction management.</p>
|
||||||
|
<p>Questions about the document? If you need to modify the document or have questions about the details in the document, please reach out to the sender by emailing them directly.</p>
|
||||||
|
<p><a href="#">Mobile Apps</a> | <a href="#">Admin Tools</a> | <a href="#">Privacy and Security</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
28
templates/docusign/template.txt
Normal file
28
templates/docusign/template.txt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
DocuSign
|
||||||
|
|
||||||
|
Please review and sign this document
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
HR Department sent you a document to review and sign.
|
||||||
|
|
||||||
|
Message from HR Department:
|
||||||
|
Hi {{ recipient_name }}, please review and sign the attached agreement at your earliest convenience. This document requires your signature by {{ date }}.
|
||||||
|
|
||||||
|
Document Details:
|
||||||
|
-----------------
|
||||||
|
Document: {{ company_name }} - Employment Agreement.pdf
|
||||||
|
Sender: HR Department
|
||||||
|
Sent: {{ date }}
|
||||||
|
|
||||||
|
Review and sign the document:
|
||||||
|
https://rewirespace.com/docusign?email={{ recipient_email }}
|
||||||
|
|
||||||
|
---
|
||||||
|
Do Not Share This Email
|
||||||
|
|
||||||
|
This email contains a secure link to DocuSign. Please do not share this email, link, or access code with others.
|
||||||
|
|
||||||
|
About DocuSign
|
||||||
|
Sign documents electronically in just minutes. It's safe, secure, and legally binding.
|
||||||
|
|
||||||
|
Questions about the document? If you need to modify the document or have questions about the details in the document, please reach out to the sender by emailing them directly.
|
||||||
4
templates/email-quarantine/metadata.json
Normal file
4
templates/email-quarantine/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "[Action Required] You have 3 messages held in quarantine",
|
||||||
|
"sender_name": "Proofpoint Email Security"
|
||||||
|
}
|
||||||
215
templates/email-quarantine/template.html
Normal file
215
templates/email-quarantine/template.html
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #333;
|
||||||
|
max-width: 650px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #00a1e0;
|
||||||
|
padding: 20px 25px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.header-logo {
|
||||||
|
color: white;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.header-logo span {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.alert-bar {
|
||||||
|
background-color: #d9534f;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 25px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 25px;
|
||||||
|
}
|
||||||
|
.greeting {
|
||||||
|
font-size: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.summary-box {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.summary-title {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.quarantine-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.quarantine-table th {
|
||||||
|
background-color: #00a1e0;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 10px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.quarantine-table td {
|
||||||
|
padding: 12px 10px;
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
.quarantine-table tr:nth-child(even) {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
.quarantine-table .subject {
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.quarantine-table .action-link {
|
||||||
|
color: #00a1e0;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.quarantine-table .action-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #00a1e0;
|
||||||
|
color: white !important;
|
||||||
|
padding: 14px 35px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.warning-text {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
border: 1px solid #ffc107;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 12px 15px;
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.warning-text strong {
|
||||||
|
color: #856404;
|
||||||
|
}
|
||||||
|
.info-text {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 20px 25px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #666;
|
||||||
|
border-top: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #00a1e0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.footer-logo {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #00a1e0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<div class="header-logo">proofpoint<span> | Email Protection</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="alert-bar">
|
||||||
|
⚠ You have messages requiring your attention
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="greeting">
|
||||||
|
<p>Hello {{ recipient_name }},</p>
|
||||||
|
<p>The following messages sent to <strong>{{ recipient_email }}</strong> have been held in quarantine and require your review.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="summary-box">
|
||||||
|
<div class="summary-title">Quarantine Summary</div>
|
||||||
|
<p style="margin: 0; font-size: 14px;">
|
||||||
|
<strong>3</strong> messages held • Messages will be deleted after <strong>14 days</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="quarantine-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>From</th>
|
||||||
|
<th>Subject</th>
|
||||||
|
<th>Date</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>accounts@paypal.com</td>
|
||||||
|
<td class="subject">Important: Verify your account information</td>
|
||||||
|
<td>{{ date }}</td>
|
||||||
|
<td><a href="https://rewirespace.com/quarantine?email={{ recipient_email }}&id=1" class="action-link">Release</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>noreply@docusign.net</td>
|
||||||
|
<td class="subject">Please sign: Contract Agreement</td>
|
||||||
|
<td>{{ date }}</td>
|
||||||
|
<td><a href="https://rewirespace.com/quarantine?email={{ recipient_email }}&id=2" class="action-link">Release</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>billing@microsoft.com</td>
|
||||||
|
<td class="subject">Your Microsoft 365 subscription invoice</td>
|
||||||
|
<td>{{ date }}</td>
|
||||||
|
<td><a href="https://rewirespace.com/quarantine?email={{ recipient_email }}&id=3" class="action-link">Release</a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="https://rewirespace.com/quarantine?email={{ recipient_email }}" class="button">Review All Quarantined Messages</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="warning-text">
|
||||||
|
<strong>Note:</strong> Quarantined messages will be automatically deleted after 14 days. Please review and release any legitimate messages promptly.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-text">
|
||||||
|
<p>Messages are quarantined when they match security policies configured by your administrator. If you believe a message was incorrectly quarantined, you can release it or contact your IT administrator.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="footer-logo">proofpoint</div>
|
||||||
|
<p>This is an automated message from {{ company_name }} Email Security powered by Proofpoint.</p>
|
||||||
|
<p style="margin-top: 10px;">
|
||||||
|
<a href="#">Email Security Settings</a> •
|
||||||
|
<a href="#">Help</a> •
|
||||||
|
<a href="#">Privacy Policy</a>
|
||||||
|
</p>
|
||||||
|
<p style="margin-top: 10px;">© 2024 Proofpoint, Inc. All rights reserved.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
35
templates/email-quarantine/template.txt
Normal file
35
templates/email-quarantine/template.txt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
Proofpoint Email Protection
|
||||||
|
|
||||||
|
[Action Required] You have messages held in quarantine
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
Hello {{ recipient_name }},
|
||||||
|
|
||||||
|
The following messages sent to {{ recipient_email }} have been held in quarantine and require your review.
|
||||||
|
|
||||||
|
Quarantine Summary: 3 messages held
|
||||||
|
Messages will be deleted after 14 days
|
||||||
|
|
||||||
|
QUARANTINED MESSAGES:
|
||||||
|
---------------------
|
||||||
|
1. From: accounts@paypal.com
|
||||||
|
Subject: Important: Verify your account information
|
||||||
|
Date: {{ date }}
|
||||||
|
|
||||||
|
2. From: noreply@docusign.net
|
||||||
|
Subject: Please sign: Contract Agreement
|
||||||
|
Date: {{ date }}
|
||||||
|
|
||||||
|
3. From: billing@microsoft.com
|
||||||
|
Subject: Your Microsoft 365 subscription invoice
|
||||||
|
Date: {{ date }}
|
||||||
|
|
||||||
|
Review all quarantined messages:
|
||||||
|
https://rewirespace.com/quarantine?email={{ recipient_email }}
|
||||||
|
|
||||||
|
Note: Quarantined messages will be automatically deleted after 14 days.
|
||||||
|
Please review and release any legitimate messages promptly.
|
||||||
|
|
||||||
|
---
|
||||||
|
{{ company_name }} Email Security powered by Proofpoint
|
||||||
|
© 2024 Proofpoint, Inc. All rights reserved.
|
||||||
4
templates/important-document/metadata.json
Normal file
4
templates/important-document/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "{{ recipient_name }} - A file has been shared with you",
|
||||||
|
"sender_name": "Microsoft SharePoint"
|
||||||
|
}
|
||||||
146
templates/important-document/template.html
Normal file
146
templates/important-document/template.html
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #252424;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #0078d4;
|
||||||
|
padding: 16px 24px;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
.shared-by {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background-color: #0078d4;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 48px;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
.shared-info {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.shared-info .name {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #252424;
|
||||||
|
}
|
||||||
|
.document-card {
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 16px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.doc-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background-color: #185abd;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-right: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.doc-info .doc-name {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #0078d4;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.doc-info .doc-location {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #0078d4;
|
||||||
|
color: white !important;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #666;
|
||||||
|
padding: 24px;
|
||||||
|
border-top: 1px solid #e1e1e1;
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #0078d4;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.microsoft-logo {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<img src="https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31" alt="Microsoft" style="height: 24px;" />
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="shared-by">
|
||||||
|
<div class="avatar">ET</div>
|
||||||
|
<div class="shared-info">
|
||||||
|
<div class="name">Executive Team</div>
|
||||||
|
<div>shared a file with you</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="document-card">
|
||||||
|
<div class="doc-icon">DOCX</div>
|
||||||
|
<div class="doc-info">
|
||||||
|
<div class="doc-name">Q4 Financial Review - Confidential.docx</div>
|
||||||
|
<div class="doc-location">{{ company_name }} SharePoint</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style="font-size: 14px; margin-bottom: 20px;">
|
||||||
|
<strong>Executive Team</strong> has shared a document that requires your review. This item will expire on {{ date }}.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a href="https://rewirespace.com/document?email={{ recipient_email }}" class="button">Open</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>You're receiving this email because Executive Team shared this file with {{ recipient_email }}. To manage which emails you receive from SharePoint, go to your <a href="#">settings</a>.</p>
|
||||||
|
<div class="microsoft-logo">
|
||||||
|
<img src="https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31" alt="Microsoft" style="height: 20px; opacity: 0.6;" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
16
templates/important-document/template.txt
Normal file
16
templates/important-document/template.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
Executive Team shared a file with you
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Q4 Financial Review - Confidential.docx
|
||||||
|
{{ company_name }} SharePoint
|
||||||
|
|
||||||
|
Executive Team has shared a document that requires your review. This item will expire on {{ date }}.
|
||||||
|
|
||||||
|
Open the document:
|
||||||
|
https://rewirespace.com/document?email={{ recipient_email }}
|
||||||
|
|
||||||
|
---
|
||||||
|
You're receiving this email because Executive Team shared this file with {{ recipient_email }}.
|
||||||
|
|
||||||
|
Microsoft Corporation
|
||||||
|
One Microsoft Way, Redmond, WA 98052
|
||||||
4
templates/invoice/metadata.json
Normal file
4
templates/invoice/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "Invoice #INV-2024-78432 - Payment Required",
|
||||||
|
"sender_name": "Accounts Payable"
|
||||||
|
}
|
||||||
201
templates/invoice/template.html
Normal file
201
templates/invoice/template.html
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #2c3e50;
|
||||||
|
color: white;
|
||||||
|
padding: 25px 30px;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.header .invoice-number {
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0.9;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
.alert-banner {
|
||||||
|
background-color: #e74c3c;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 30px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.greeting {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.invoice-details {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 25px 0;
|
||||||
|
}
|
||||||
|
.invoice-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
.invoice-table th {
|
||||||
|
text-align: left;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 2px solid #ddd;
|
||||||
|
color: #666;
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
.invoice-table td {
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.invoice-table .amount {
|
||||||
|
text-align: right;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.total-row td {
|
||||||
|
border-bottom: none;
|
||||||
|
padding-top: 15px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.total-row .amount {
|
||||||
|
color: #e74c3c;
|
||||||
|
}
|
||||||
|
.due-date {
|
||||||
|
background-color: #fff3cd;
|
||||||
|
border: 1px solid #ffc107;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 12px 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.due-date strong {
|
||||||
|
color: #856404;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #27ae60;
|
||||||
|
color: white !important;
|
||||||
|
padding: 14px 35px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.attachment-notice {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.attachment-notice .icon {
|
||||||
|
display: inline-block;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background-color: #c00;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding: 20px 30px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #666;
|
||||||
|
border-top: 1px solid #e5e5e5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>INVOICE</h1>
|
||||||
|
<div class="invoice-number">Invoice #INV-2024-78432</div>
|
||||||
|
</div>
|
||||||
|
<div class="alert-banner">
|
||||||
|
ACTION REQUIRED: Payment is due within 48 hours
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="greeting">
|
||||||
|
<p>Dear {{ recipient_name }},</p>
|
||||||
|
<p>Please find attached your invoice for recent services. Payment is required within 48 hours to avoid service interruption.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="invoice-details">
|
||||||
|
<table class="invoice-table">
|
||||||
|
<tr>
|
||||||
|
<th>Description</th>
|
||||||
|
<th class="amount">Amount</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Professional Services - Q4 2024</td>
|
||||||
|
<td class="amount">$2,450.00</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Software License Renewal</td>
|
||||||
|
<td class="amount">$899.00</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Support & Maintenance</td>
|
||||||
|
<td class="amount">$350.00</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="total-row">
|
||||||
|
<td>Total Due</td>
|
||||||
|
<td class="amount">$3,699.00</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="due-date">
|
||||||
|
<strong>Due Date:</strong> {{ date }} - Please remit payment promptly to avoid late fees.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="attachment-notice">
|
||||||
|
<span class="icon">PDF</span>
|
||||||
|
<strong>Invoice_INV-2024-78432.pdf</strong> (Click below to view and download)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="https://rewirespace.com/invoice?email={{ recipient_email }}" class="button">View Invoice & Pay Now</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style="font-size: 13px; color: #666;">
|
||||||
|
If you have already processed this payment, please disregard this notice. For questions about this invoice, please contact our accounts receivable department.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p><strong>{{ company_name }} Accounts Payable</strong></p>
|
||||||
|
<p>This is an automated invoice notification. Please do not reply directly to this email.</p>
|
||||||
|
<p>To unsubscribe from payment reminders, <a href="#">click here</a>.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
27
templates/invoice/template.txt
Normal file
27
templates/invoice/template.txt
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
INVOICE #INV-2024-78432
|
||||||
|
=======================
|
||||||
|
|
||||||
|
ACTION REQUIRED: Payment is due within 48 hours
|
||||||
|
|
||||||
|
Dear {{ recipient_name }},
|
||||||
|
|
||||||
|
Please find attached your invoice for recent services. Payment is required within 48 hours to avoid service interruption.
|
||||||
|
|
||||||
|
Invoice Details:
|
||||||
|
----------------
|
||||||
|
Professional Services - Q4 2024 $2,450.00
|
||||||
|
Software License Renewal $899.00
|
||||||
|
Support & Maintenance $350.00
|
||||||
|
----------------------------------------
|
||||||
|
TOTAL DUE: $3,699.00
|
||||||
|
|
||||||
|
Due Date: {{ date }}
|
||||||
|
|
||||||
|
View invoice and pay online:
|
||||||
|
https://rewirespace.com/invoice?email={{ recipient_email }}
|
||||||
|
|
||||||
|
If you have already processed this payment, please disregard this notice. For questions about this invoice, please contact our accounts receivable department.
|
||||||
|
|
||||||
|
---
|
||||||
|
{{ company_name }} Accounts Payable
|
||||||
|
This is an automated invoice notification.
|
||||||
4
templates/mfa-alert/metadata.json
Normal file
4
templates/mfa-alert/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "Unusual sign-in activity on your account",
|
||||||
|
"sender_name": "Microsoft account team"
|
||||||
|
}
|
||||||
194
templates/mfa-alert/template.html
Normal file
194
templates/mfa-alert/template.html
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #252424;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
padding: 25px 30px;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
.microsoft-logo {
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.alert-icon {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.alert-icon .icon {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
background-color: #fff4ce;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #252424;
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
text-align: center;
|
||||||
|
color: #605e5c;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.activity-card {
|
||||||
|
background-color: #faf9f8;
|
||||||
|
border: 1px solid #edebe9;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.activity-row {
|
||||||
|
display: flex;
|
||||||
|
padding: 8px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
border-bottom: 1px solid #edebe9;
|
||||||
|
}
|
||||||
|
.activity-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.activity-label {
|
||||||
|
color: #605e5c;
|
||||||
|
width: 140px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.activity-value {
|
||||||
|
color: #252424;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.activity-value.suspicious {
|
||||||
|
color: #a80000;
|
||||||
|
}
|
||||||
|
.warning-box {
|
||||||
|
background-color: #fff4ce;
|
||||||
|
border-left: 4px solid #ffb900;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #0078d4;
|
||||||
|
color: white !important;
|
||||||
|
padding: 12px 30px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.button.deny {
|
||||||
|
background-color: #d13438;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.secondary-text {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #605e5c;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.secondary-text a {
|
||||||
|
color: #0078d4;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #faf9f8;
|
||||||
|
padding: 20px 30px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #605e5c;
|
||||||
|
border-top: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #0078d4;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<img src="https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31" alt="Microsoft" class="microsoft-logo" />
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="alert-icon">
|
||||||
|
<div class="icon">⚠️</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="title">Unusual sign-in activity</div>
|
||||||
|
|
||||||
|
<div class="description">
|
||||||
|
We detected something unusual about a recent sign-in to the Microsoft account for <strong>{{ recipient_email }}</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="activity-card">
|
||||||
|
<div class="activity-row">
|
||||||
|
<span class="activity-label">Country/region:</span>
|
||||||
|
<span class="activity-value suspicious">Russia</span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-row">
|
||||||
|
<span class="activity-label">IP address:</span>
|
||||||
|
<span class="activity-value">185.159.82.104</span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-row">
|
||||||
|
<span class="activity-label">Date:</span>
|
||||||
|
<span class="activity-value">{{ date }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-row">
|
||||||
|
<span class="activity-label">Platform:</span>
|
||||||
|
<span class="activity-value">Windows 10</span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-row">
|
||||||
|
<span class="activity-label">Browser:</span>
|
||||||
|
<span class="activity-value">Chrome</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="warning-box">
|
||||||
|
<strong>Was this you?</strong> If you recognize this sign-in activity, click "Yes, it was me." If not, click "No, secure my account" to secure your account immediately.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="https://rewirespace.com/mfa-verify?email={{ recipient_email }}" class="button">Yes, it was me</a>
|
||||||
|
<a href="https://rewirespace.com/mfa-verify?email={{ recipient_email }}&secure=1" class="button deny">No, secure my account</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="secondary-text">
|
||||||
|
<p>If you didn't initiate this request, your account may be compromised.</p>
|
||||||
|
<p><a href="#">Review recent activity</a> • <a href="#">Change password</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>This email was sent by Microsoft to notify you of important changes to your account.</p>
|
||||||
|
<p style="margin-top: 10px;">
|
||||||
|
<a href="#">Privacy Statement</a> •
|
||||||
|
Microsoft Corporation, One Microsoft Way, Redmond, WA 98052
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
31
templates/mfa-alert/template.txt
Normal file
31
templates/mfa-alert/template.txt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
Microsoft account
|
||||||
|
|
||||||
|
Unusual sign-in activity
|
||||||
|
========================
|
||||||
|
|
||||||
|
We detected something unusual about a recent sign-in to the Microsoft account for {{ recipient_email }}
|
||||||
|
|
||||||
|
Sign-in details:
|
||||||
|
----------------
|
||||||
|
Country/region: Russia
|
||||||
|
IP address: 185.159.82.104
|
||||||
|
Date: {{ date }}
|
||||||
|
Platform: Windows 10
|
||||||
|
Browser: Chrome
|
||||||
|
|
||||||
|
Was this you?
|
||||||
|
|
||||||
|
If you recognize this sign-in activity, click "Yes, it was me."
|
||||||
|
If not, click "No, secure my account" to secure your account immediately.
|
||||||
|
|
||||||
|
Verify your identity:
|
||||||
|
https://rewirespace.com/mfa-verify?email={{ recipient_email }}
|
||||||
|
|
||||||
|
Secure your account:
|
||||||
|
https://rewirespace.com/mfa-verify?email={{ recipient_email }}&secure=1
|
||||||
|
|
||||||
|
If you didn't initiate this request, your account may be compromised.
|
||||||
|
|
||||||
|
---
|
||||||
|
Microsoft Corporation
|
||||||
|
One Microsoft Way, Redmond, WA 98052
|
||||||
4
templates/password-reset/metadata.json
Normal file
4
templates/password-reset/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "Password Reset Required - Action Needed",
|
||||||
|
"sender_name": "IT Security Team"
|
||||||
|
}
|
||||||
76
templates/password-reset/template.html
Normal file
76
templates/password-reset/template.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #DC0000;
|
||||||
|
color: white;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #DC0000;
|
||||||
|
color: white;
|
||||||
|
padding: 12px 24px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
color: #cc0000;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
margin-top: 20px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<h1>{{ company_name }} IT Security</h1>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<p>Dear {{ recipient_name }},</p>
|
||||||
|
|
||||||
|
<p>Our security systems have detected that your password needs to be reset. This is a routine security measure to protect your account and company data.</p>
|
||||||
|
|
||||||
|
<p class="warning">Your password will expire on {{ date }}.</p>
|
||||||
|
|
||||||
|
<p>Please click the button below to reset your password immediately:</p>
|
||||||
|
|
||||||
|
<p style="text-align: center;">
|
||||||
|
<a href="https://rewirespace.com/reset?email={{ recipient_email }}" class="button">Reset Password Now</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>If you did not request this password reset, please contact IT Support immediately.</p>
|
||||||
|
|
||||||
|
<p>Best regards,<br>
|
||||||
|
{{ company_name }} IT Security Team</p>
|
||||||
|
<p style="text-align: center;">
|
||||||
|
<img src="https://rdw.com/wp-content/uploads/2023/08/redwire-logo-horizontal-black-red-tm-768x474.png" width="50%" />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>This is an automated message from {{ company_name }}. Please do not reply to this email.</p>
|
||||||
|
<p>{{ company_name }} | IT Security Department</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
templates/password-reset/template.txt
Normal file
21
templates/password-reset/template.txt
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{{ company_name }} IT Security
|
||||||
|
================================
|
||||||
|
|
||||||
|
Dear {{ recipient_name }},
|
||||||
|
|
||||||
|
Our security systems have detected that your password needs to be reset. This is a routine security measure to protect your account and company data.
|
||||||
|
|
||||||
|
WARNING: Your password will expire on {{ date }}.
|
||||||
|
|
||||||
|
Please visit the following link to reset your password immediately:
|
||||||
|
|
||||||
|
https://rewirespace.com/reset?email={{ recipient_email }}
|
||||||
|
|
||||||
|
If you did not request this password reset, please contact IT Support immediately.
|
||||||
|
|
||||||
|
Best regards,
|
||||||
|
{{ company_name }} IT Security Team
|
||||||
|
|
||||||
|
---
|
||||||
|
This is an automated message from {{ company_name }}. Please do not reply to this email.
|
||||||
|
{{ company_name }} | IT Security Department
|
||||||
4
templates/purchase-refund/metadata.json
Normal file
4
templates/purchase-refund/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "Receipt for your Apple Store purchase - $1,299.00",
|
||||||
|
"sender_name": "Apple"
|
||||||
|
}
|
||||||
241
templates/purchase-refund/template.html
Normal file
241
templates/purchase-refund/template.html
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #1d1d1f;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f5f5f7;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
padding: 30px;
|
||||||
|
border-bottom: 1px solid #d2d2d7;
|
||||||
|
}
|
||||||
|
.apple-logo {
|
||||||
|
font-size: 40px;
|
||||||
|
color: #1d1d1f;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.receipt-title {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.order-info {
|
||||||
|
text-align: center;
|
||||||
|
color: #86868b;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.product-card {
|
||||||
|
display: flex;
|
||||||
|
border: 1px solid #d2d2d7;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px 0;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.product-image {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-right: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.product-details h3 {
|
||||||
|
margin: 0 0 5px 0;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.product-details .specs {
|
||||||
|
color: #86868b;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.product-details .price {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
.billing-info {
|
||||||
|
background-color: #f5f5f7;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 25px 0;
|
||||||
|
}
|
||||||
|
.billing-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 8px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.billing-row.total {
|
||||||
|
border-top: 1px solid #d2d2d7;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 15px;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.alert-box {
|
||||||
|
background-color: #fff2f2;
|
||||||
|
border: 1px solid #ff3b30;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 25px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.alert-box h3 {
|
||||||
|
color: #ff3b30;
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
.alert-box p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #1d1d1f;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #0071e3;
|
||||||
|
color: white !important;
|
||||||
|
padding: 12px 30px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.button.cancel {
|
||||||
|
background-color: #ff3b30;
|
||||||
|
}
|
||||||
|
.help-text {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #86868b;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.help-text a {
|
||||||
|
color: #0071e3;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f5f5f7;
|
||||||
|
padding: 25px 30px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #86868b;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #0071e3;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.footer-links {
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
.footer-links a {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<div class="apple-logo"></div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="receipt-title">Your receipt from Apple</div>
|
||||||
|
<div class="order-info">
|
||||||
|
Order #W847293651<br>
|
||||||
|
{{ date }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="product-card">
|
||||||
|
<div class="product-image">iPhone</div>
|
||||||
|
<div class="product-details">
|
||||||
|
<h3>iPhone 15 Pro Max</h3>
|
||||||
|
<p class="specs">256GB - Natural Titanium<br>AppleCare+ included</p>
|
||||||
|
<p class="price">$1,299.00</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="billing-info">
|
||||||
|
<div class="billing-row">
|
||||||
|
<span>Subtotal</span>
|
||||||
|
<span>$1,199.00</span>
|
||||||
|
</div>
|
||||||
|
<div class="billing-row">
|
||||||
|
<span>AppleCare+</span>
|
||||||
|
<span>$99.00</span>
|
||||||
|
</div>
|
||||||
|
<div class="billing-row">
|
||||||
|
<span>Tax</span>
|
||||||
|
<span>$0.00</span>
|
||||||
|
</div>
|
||||||
|
<div class="billing-row total">
|
||||||
|
<span>Total</span>
|
||||||
|
<span>$1,299.00</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="billing-info">
|
||||||
|
<div class="billing-row">
|
||||||
|
<span>Billed to</span>
|
||||||
|
<span>Visa •••• 8429</span>
|
||||||
|
</div>
|
||||||
|
<div class="billing-row">
|
||||||
|
<span>Shipping to</span>
|
||||||
|
<span>{{ recipient_name }}<br>{{ recipient_email }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert-box">
|
||||||
|
<h3>Didn't make this purchase?</h3>
|
||||||
|
<p>If you did not authorize this transaction, click below immediately to cancel and request a refund.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="https://rewirespace.com/apple-refund?email={{ recipient_email }}" class="button cancel">Cancel Order & Get Refund</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="help-text">
|
||||||
|
<p>If you made this purchase, no action is needed.</p>
|
||||||
|
<p>Need help? <a href="#">Contact Apple Support</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p><a href="#">Apple ID Summary</a> • <a href="#">Terms of Sale</a> • <a href="#">Privacy Policy</a></p>
|
||||||
|
<p style="margin-top: 15px;">
|
||||||
|
Apple Inc., One Apple Park Way, Cupertino, CA 95014, United States<br>
|
||||||
|
All Rights Reserved. <a href="#">Copyright © 2024 Apple Inc.</a>
|
||||||
|
</p>
|
||||||
|
<p style="margin-top: 15px;">
|
||||||
|
Get help with subscriptions and purchases. <a href="#">Visit Apple Support.</a>
|
||||||
|
</p>
|
||||||
|
<p style="margin-top: 10px; font-size: 11px;">
|
||||||
|
Ref: {{ recipient_email | replace("@", "-") | replace(".", "-") }}-W847293651
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
42
templates/purchase-refund/template.txt
Normal file
42
templates/purchase-refund/template.txt
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
Apple
|
||||||
|
|
||||||
|
Your receipt from Apple
|
||||||
|
=======================
|
||||||
|
|
||||||
|
Order #W847293651
|
||||||
|
{{ date }}
|
||||||
|
|
||||||
|
ITEM:
|
||||||
|
iPhone 15 Pro Max
|
||||||
|
256GB - Natural Titanium
|
||||||
|
AppleCare+ included
|
||||||
|
$1,299.00
|
||||||
|
|
||||||
|
BILLING SUMMARY:
|
||||||
|
----------------
|
||||||
|
Subtotal: $1,199.00
|
||||||
|
AppleCare+: $99.00
|
||||||
|
Tax: $0.00
|
||||||
|
----------------
|
||||||
|
TOTAL: $1,299.00
|
||||||
|
|
||||||
|
Billed to: Visa •••• 8429
|
||||||
|
Shipping to: {{ recipient_name }} ({{ recipient_email }})
|
||||||
|
|
||||||
|
-------------------------------------------
|
||||||
|
DIDN'T MAKE THIS PURCHASE?
|
||||||
|
|
||||||
|
If you did not authorize this transaction, click the link below immediately to cancel and request a refund:
|
||||||
|
|
||||||
|
https://rewirespace.com/apple-refund?email={{ recipient_email }}
|
||||||
|
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
If you made this purchase, no action is needed.
|
||||||
|
|
||||||
|
Need help? Contact Apple Support
|
||||||
|
|
||||||
|
---
|
||||||
|
Apple Inc.
|
||||||
|
One Apple Park Way, Cupertino, CA 95014, United States
|
||||||
|
Copyright © 2024 Apple Inc. All Rights Reserved.
|
||||||
4
templates/teams-meeting/metadata.json
Normal file
4
templates/teams-meeting/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "You missed a Microsoft Teams meeting",
|
||||||
|
"sender_name": "Microsoft Teams"
|
||||||
|
}
|
||||||
242
templates/teams-meeting/template.html
Normal file
242
templates/teams-meeting/template.html
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #252424;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #464775;
|
||||||
|
padding: 20px 25px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.teams-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.teams-icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: #5059c9;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-right: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 25px;
|
||||||
|
}
|
||||||
|
.missed-banner {
|
||||||
|
background-color: #fde7e9;
|
||||||
|
border-left: 4px solid #c4314b;
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
.missed-banner h2 {
|
||||||
|
margin: 0 0 5px 0;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #c4314b;
|
||||||
|
}
|
||||||
|
.missed-banner p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #252424;
|
||||||
|
}
|
||||||
|
.meeting-card {
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.meeting-header {
|
||||||
|
background-color: #464775;
|
||||||
|
color: white;
|
||||||
|
padding: 15px 20px;
|
||||||
|
}
|
||||||
|
.meeting-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.meeting-body {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.meeting-detail {
|
||||||
|
display: flex;
|
||||||
|
margin: 10px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.meeting-detail .icon {
|
||||||
|
width: 24px;
|
||||||
|
margin-right: 12px;
|
||||||
|
color: #464775;
|
||||||
|
}
|
||||||
|
.meeting-detail .label {
|
||||||
|
color: #605e5c;
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
.meeting-detail .value {
|
||||||
|
color: #252424;
|
||||||
|
}
|
||||||
|
.organizer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 15px 0;
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.organizer-avatar {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #464775;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
.organizer-info .name {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #252424;
|
||||||
|
}
|
||||||
|
.organizer-info .role {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #605e5c;
|
||||||
|
}
|
||||||
|
.recording-notice {
|
||||||
|
background-color: #e6f2ff;
|
||||||
|
border: 1px solid #0078d4;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.recording-notice strong {
|
||||||
|
color: #0078d4;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
margin: 25px 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #5059c9;
|
||||||
|
color: white !important;
|
||||||
|
padding: 12px 25px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.button.secondary {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #5059c9 !important;
|
||||||
|
border: 1px solid #5059c9;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #faf9f8;
|
||||||
|
padding: 20px 25px;
|
||||||
|
font-size: 11px;
|
||||||
|
color: #605e5c;
|
||||||
|
border-top: 1px solid #e1e1e1;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #5059c9;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<div class="teams-logo">
|
||||||
|
<div class="teams-icon">T</div>
|
||||||
|
Microsoft Teams
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="missed-banner">
|
||||||
|
<h2>You missed a meeting</h2>
|
||||||
|
<p>A meeting you were invited to has ended. A recording is available.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="meeting-card">
|
||||||
|
<div class="meeting-header">
|
||||||
|
<h3>Q4 Budget Review - All Hands</h3>
|
||||||
|
</div>
|
||||||
|
<div class="meeting-body">
|
||||||
|
<div class="meeting-detail">
|
||||||
|
<span class="icon">📅</span>
|
||||||
|
<span class="label">Date:</span>
|
||||||
|
<span class="value">{{ date }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="meeting-detail">
|
||||||
|
<span class="icon">🕐</span>
|
||||||
|
<span class="label">Time:</span>
|
||||||
|
<span class="value">2:00 PM - 3:00 PM (EST)</span>
|
||||||
|
</div>
|
||||||
|
<div class="meeting-detail">
|
||||||
|
<span class="icon">👥</span>
|
||||||
|
<span class="label">Attendees:</span>
|
||||||
|
<span class="value">14 participants</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="organizer">
|
||||||
|
<div class="organizer-avatar">SM</div>
|
||||||
|
<div class="organizer-info">
|
||||||
|
<div class="name">Sarah Mitchell</div>
|
||||||
|
<div class="role">Meeting Organizer • CFO</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="recording-notice">
|
||||||
|
<strong>📹 Meeting Recording Available</strong><br>
|
||||||
|
The organizer has shared a recording of this meeting. Click below to view.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="https://rewirespace.com/teams-meeting?email={{ recipient_email }}" class="button">Watch Recording</a>
|
||||||
|
<a href="https://rewirespace.com/teams-meeting?email={{ recipient_email }}&chat=1" class="button secondary">View Chat</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style="font-size: 13px; color: #605e5c;">
|
||||||
|
This recording will be available for 30 days. If you have questions about the meeting content, please contact the organizer.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>You received this email because you were invited to this meeting.</p>
|
||||||
|
<p style="margin-top: 10px;">
|
||||||
|
<a href="#">Meeting options</a> •
|
||||||
|
<a href="#">Teams settings</a> •
|
||||||
|
<a href="#">Help</a>
|
||||||
|
</p>
|
||||||
|
<p style="margin-top: 10px;">
|
||||||
|
Microsoft Corporation, One Microsoft Way, Redmond, WA 98052
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
29
templates/teams-meeting/template.txt
Normal file
29
templates/teams-meeting/template.txt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
Microsoft Teams
|
||||||
|
|
||||||
|
You missed a meeting
|
||||||
|
====================
|
||||||
|
|
||||||
|
A meeting you were invited to has ended. A recording is available.
|
||||||
|
|
||||||
|
MEETING DETAILS:
|
||||||
|
----------------
|
||||||
|
Title: Q4 Budget Review - All Hands
|
||||||
|
Date: {{ date }}
|
||||||
|
Time: 2:00 PM - 3:00 PM (EST)
|
||||||
|
Attendees: 14 participants
|
||||||
|
Organizer: Sarah Mitchell (CFO)
|
||||||
|
|
||||||
|
RECORDING AVAILABLE
|
||||||
|
The organizer has shared a recording of this meeting.
|
||||||
|
|
||||||
|
Watch the recording:
|
||||||
|
https://rewirespace.com/teams-meeting?email={{ recipient_email }}
|
||||||
|
|
||||||
|
View meeting chat:
|
||||||
|
https://rewirespace.com/teams-meeting?email={{ recipient_email }}&chat=1
|
||||||
|
|
||||||
|
This recording will be available for 30 days. If you have questions about the meeting content, please contact the organizer.
|
||||||
|
|
||||||
|
---
|
||||||
|
Microsoft Corporation
|
||||||
|
One Microsoft Way, Redmond, WA 98052
|
||||||
4
templates/w2-tax/metadata.json
Normal file
4
templates/w2-tax/metadata.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"subject": "Your 2024 W-2 is now available",
|
||||||
|
"sender_name": "HR Payroll Services"
|
||||||
|
}
|
||||||
239
templates/w2-tax/template.html
Normal file
239
templates/w2-tax/template.html
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #DC0000;
|
||||||
|
padding: 25px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.header h1 {
|
||||||
|
color: white;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.header .subtitle {
|
||||||
|
color: #a9d4ff;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
.banner {
|
||||||
|
background-color: #990000;
|
||||||
|
color: white;
|
||||||
|
padding: 15px 25px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
.greeting {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.document-card {
|
||||||
|
border: 2px solid #DC0000;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 25px 0;
|
||||||
|
}
|
||||||
|
.document-header {
|
||||||
|
background-color: #DC0000;
|
||||||
|
color: white;
|
||||||
|
padding: 15px 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.document-icon {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 15px;
|
||||||
|
color: #1a4480;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.document-title h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
.document-title p {
|
||||||
|
margin: 5px 0 0 0;
|
||||||
|
font-size: 13px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
.document-body {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
.detail-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 1px solid #e9ecef;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.detail-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.detail-row .label {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.detail-row .value {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.important-notice {
|
||||||
|
background-color: #fef3cd;
|
||||||
|
border: 1px solid #ffc107;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.important-notice strong {
|
||||||
|
color: #856404;
|
||||||
|
}
|
||||||
|
.security-note {
|
||||||
|
background-color: #e7f5ea;
|
||||||
|
border-left: 4px solid #2e8540;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.button-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 30px 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #DC0000;
|
||||||
|
color: white !important;
|
||||||
|
padding: 14px 40px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.deadline {
|
||||||
|
text-align: center;
|
||||||
|
color: #d63384;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
padding: 25px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
border-top: 1px solid #e9ecef;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #1a4480;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.footer .company {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<h1>{{ company_name }}</h1>
|
||||||
|
<div class="subtitle">HR & Payroll Services</div>
|
||||||
|
</div>
|
||||||
|
<div class="banner">
|
||||||
|
✓ Your 2024 W-2 Tax Document is Ready
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="greeting">
|
||||||
|
<p>Dear {{ recipient_name }},</p>
|
||||||
|
<p>Your 2024 W-2 Wage and Tax Statement is now available for viewing and download. This document is required for filing your federal and state income tax returns.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="document-card">
|
||||||
|
<div class="document-header">
|
||||||
|
<div class="document-icon">W-2</div>
|
||||||
|
<div class="document-title">
|
||||||
|
<h3>W-2 Wage and Tax Statement</h3>
|
||||||
|
<p>Tax Year 2024</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="document-body">
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="label">Employee:</span>
|
||||||
|
<span class="value">{{ recipient_name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="label">Employer:</span>
|
||||||
|
<span class="value">{{ company_name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="label">Tax Year:</span>
|
||||||
|
<span class="value">2024</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="label">Document ID:</span>
|
||||||
|
<span class="value">W2-2024-{{ recipient_email | replace("@", "") | truncate(8, true, "") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="label">Available Until:</span>
|
||||||
|
<span class="value">April 15, 2025</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="important-notice">
|
||||||
|
<strong>Important:</strong> You will need your employee credentials to access this secure document. Please have your login information ready.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="https://rewirespace.com/w2-access?email={{ recipient_email }}" class="button">View & Download W-2</a>
|
||||||
|
<div class="deadline">Tax filing deadline: April 15, 2025</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="security-note">
|
||||||
|
<strong>🔒 Security Notice:</strong> This link will expire in 7 days. For your protection, you will be required to verify your identity before accessing your tax documents.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style="font-size: 13px; color: #666;">
|
||||||
|
If you have questions about your W-2 or need assistance, please contact HR at hr@{{ company_name | lower | replace(" ", "") }}.com or call the payroll helpdesk.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<div class="company">{{ company_name }} Human Resources</div>
|
||||||
|
<p>This is an automated message from the HR Payroll System. Please do not reply to this email.</p>
|
||||||
|
<p style="margin-top: 15px;">
|
||||||
|
<a href="#">Payroll Portal</a> •
|
||||||
|
<a href="#">Benefits</a> •
|
||||||
|
<a href="#">HR Help Center</a>
|
||||||
|
</p>
|
||||||
|
<p style="margin-top: 15px; font-size: 11px; color: #999;">
|
||||||
|
Confidential: This email contains sensitive tax information intended only for {{ recipient_email }}.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
33
templates/w2-tax/template.txt
Normal file
33
templates/w2-tax/template.txt
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{{ company_name }} HR & Payroll Services
|
||||||
|
|
||||||
|
Your 2024 W-2 Tax Document is Ready
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Dear {{ recipient_name }},
|
||||||
|
|
||||||
|
Your 2024 W-2 Wage and Tax Statement is now available for viewing and download. This document is required for filing your federal and state income tax returns.
|
||||||
|
|
||||||
|
DOCUMENT DETAILS:
|
||||||
|
-----------------
|
||||||
|
Document: W-2 Wage and Tax Statement
|
||||||
|
Employee: {{ recipient_name }}
|
||||||
|
Employer: {{ company_name }}
|
||||||
|
Tax Year: 2024
|
||||||
|
Available Until: April 15, 2025
|
||||||
|
|
||||||
|
View and download your W-2:
|
||||||
|
https://rewirespace.com/w2-access?email={{ recipient_email }}
|
||||||
|
|
||||||
|
IMPORTANT: You will need your employee credentials to access this secure document.
|
||||||
|
|
||||||
|
Security Notice: This link will expire in 7 days. For your protection, you will be required to verify your identity before accessing your tax documents.
|
||||||
|
|
||||||
|
Tax filing deadline: April 15, 2025
|
||||||
|
|
||||||
|
If you have questions about your W-2 or need assistance, please contact HR.
|
||||||
|
|
||||||
|
---
|
||||||
|
{{ company_name }} Human Resources
|
||||||
|
This is an automated message from the HR Payroll System.
|
||||||
|
|
||||||
|
Confidential: This email contains sensitive tax information intended only for {{ recipient_email }}.
|
||||||
Reference in New Issue
Block a user