From a25b81224e94381777a8c3a7900757c11936614b Mon Sep 17 00:00:00 2001 From: Phillip Tarrant Date: Wed, 31 Dec 2025 06:07:37 -0600 Subject: [PATCH] first commit --- .env.example | 9 + .gitignore | 73 +++++++ CLAUDE.md | 52 +++++ README.md | 93 ++++++++ recipients.csv | 2 + requirements.txt | 4 + src/__init__.py | 1 + src/config.py | 27 +++ src/csv_loader.py | 77 +++++++ src/email_sender.py | 103 +++++++++ src/main.py | 171 +++++++++++++++ src/template_loader.py | 111 ++++++++++ templates/docusign/metadata.json | 4 + templates/docusign/template.html | 210 ++++++++++++++++++ templates/docusign/template.txt | 28 +++ templates/email-quarantine/metadata.json | 4 + templates/email-quarantine/template.html | 215 ++++++++++++++++++ templates/email-quarantine/template.txt | 35 +++ templates/important-document/metadata.json | 4 + templates/important-document/template.html | 146 +++++++++++++ templates/important-document/template.txt | 16 ++ templates/invoice/metadata.json | 4 + templates/invoice/template.html | 201 +++++++++++++++++ templates/invoice/template.txt | 27 +++ templates/mfa-alert/metadata.json | 4 + templates/mfa-alert/template.html | 194 +++++++++++++++++ templates/mfa-alert/template.txt | 31 +++ templates/password-reset/metadata.json | 4 + templates/password-reset/template.html | 76 +++++++ templates/password-reset/template.txt | 21 ++ templates/purchase-refund/metadata.json | 4 + templates/purchase-refund/template.html | 241 ++++++++++++++++++++ templates/purchase-refund/template.txt | 42 ++++ templates/teams-meeting/metadata.json | 4 + templates/teams-meeting/template.html | 242 +++++++++++++++++++++ templates/teams-meeting/template.txt | 29 +++ templates/w2-tax/metadata.json | 4 + templates/w2-tax/template.html | 239 ++++++++++++++++++++ templates/w2-tax/template.txt | 33 +++ 39 files changed, 2785 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 README.md create mode 100644 recipients.csv create mode 100644 requirements.txt create mode 100644 src/__init__.py create mode 100644 src/config.py create mode 100644 src/csv_loader.py create mode 100644 src/email_sender.py create mode 100644 src/main.py create mode 100644 src/template_loader.py create mode 100644 templates/docusign/metadata.json create mode 100644 templates/docusign/template.html create mode 100644 templates/docusign/template.txt create mode 100644 templates/email-quarantine/metadata.json create mode 100644 templates/email-quarantine/template.html create mode 100644 templates/email-quarantine/template.txt create mode 100644 templates/important-document/metadata.json create mode 100644 templates/important-document/template.html create mode 100644 templates/important-document/template.txt create mode 100644 templates/invoice/metadata.json create mode 100644 templates/invoice/template.html create mode 100644 templates/invoice/template.txt create mode 100644 templates/mfa-alert/metadata.json create mode 100644 templates/mfa-alert/template.html create mode 100644 templates/mfa-alert/template.txt create mode 100644 templates/password-reset/metadata.json create mode 100644 templates/password-reset/template.html create mode 100644 templates/password-reset/template.txt create mode 100644 templates/purchase-refund/metadata.json create mode 100644 templates/purchase-refund/template.html create mode 100644 templates/purchase-refund/template.txt create mode 100644 templates/teams-meeting/metadata.json create mode 100644 templates/teams-meeting/template.html create mode 100644 templates/teams-meeting/template.txt create mode 100644 templates/w2-tax/metadata.json create mode 100644 templates/w2-tax/template.html create mode 100644 templates/w2-tax/template.txt diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..dd16521 --- /dev/null +++ b/.env.example @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de8e173 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..348de49 --- /dev/null +++ b/CLAUDE.md @@ -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 +python -m src.main send --template --to +python -m src.main send --template --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//` 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 diff --git a/README.md b/README.md new file mode 100644 index 0000000..eab2574 --- /dev/null +++ b/README.md @@ -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//` 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 | diff --git a/recipients.csv b/recipients.csv new file mode 100644 index 0000000..b39e902 --- /dev/null +++ b/recipients.csv @@ -0,0 +1,2 @@ +email,name +ptarrant@gmail.com,Phillip Tarrant diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ed09749 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +smtp2go>=1.0.0 +python-dotenv>=1.0.0 +jinja2>=3.1.0 +click>=8.1.0 diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..83ad549 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1 @@ +# Phishtest - Phishing Test System for Proofpoint TAP Testing diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..7bf9dbb --- /dev/null +++ b/src/config.py @@ -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 diff --git a/src/csv_loader.py b/src/csv_loader.py new file mode 100644 index 0000000..b135f77 --- /dev/null +++ b/src/csv_loader.py @@ -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) diff --git a/src/email_sender.py b/src/email_sender.py new file mode 100644 index 0000000..7f80891 --- /dev/null +++ b/src/email_sender.py @@ -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 diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..7a9a08f --- /dev/null +++ b/src/main.py @@ -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() diff --git a/src/template_loader.py b/src/template_loader.py new file mode 100644 index 0000000..5c7ad71 --- /dev/null +++ b/src/template_loader.py @@ -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 diff --git a/templates/docusign/metadata.json b/templates/docusign/metadata.json new file mode 100644 index 0000000..9932512 --- /dev/null +++ b/templates/docusign/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "Please DocuSign: {{ company_name }} - Agreement Document", + "sender_name": "DocuSign" +} diff --git a/templates/docusign/template.html b/templates/docusign/template.html new file mode 100644 index 0000000..0841d9c --- /dev/null +++ b/templates/docusign/template.html @@ -0,0 +1,210 @@ + + + + + + + +
+
+ +
+
+
+
+
+ +
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: + {{ company_name }} - Employment Agreement.pdf +
+
+ Sender: + hr@{{ company_name | lower | replace(" ", "") }}.com +
+
+ Sent: + {{ date }} +
+
+ + + + +
+ +
+ + diff --git a/templates/docusign/template.txt b/templates/docusign/template.txt new file mode 100644 index 0000000..02f0b58 --- /dev/null +++ b/templates/docusign/template.txt @@ -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. diff --git a/templates/email-quarantine/metadata.json b/templates/email-quarantine/metadata.json new file mode 100644 index 0000000..23b2981 --- /dev/null +++ b/templates/email-quarantine/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "[Action Required] You have 3 messages held in quarantine", + "sender_name": "Proofpoint Email Security" +} diff --git a/templates/email-quarantine/template.html b/templates/email-quarantine/template.html new file mode 100644 index 0000000..1ae9dcf --- /dev/null +++ b/templates/email-quarantine/template.html @@ -0,0 +1,215 @@ + + + + + + + +
+
+ +
+
+ ⚠ You have messages requiring your attention +
+
+
+

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 +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FromSubjectDateAction
accounts@paypal.comImportant: Verify your account information{{ date }}Release
noreply@docusign.netPlease sign: Contract Agreement{{ date }}Release
billing@microsoft.comYour Microsoft 365 subscription invoice{{ date }}Release
+ + + +
+ Note: Quarantined messages will be automatically deleted after 14 days. Please review and release any legitimate messages promptly. +
+ +
+

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.

+
+
+ +
+ + diff --git a/templates/email-quarantine/template.txt b/templates/email-quarantine/template.txt new file mode 100644 index 0000000..89caca2 --- /dev/null +++ b/templates/email-quarantine/template.txt @@ -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. diff --git a/templates/important-document/metadata.json b/templates/important-document/metadata.json new file mode 100644 index 0000000..402d15e --- /dev/null +++ b/templates/important-document/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "{{ recipient_name }} - A file has been shared with you", + "sender_name": "Microsoft SharePoint" +} diff --git a/templates/important-document/template.html b/templates/important-document/template.html new file mode 100644 index 0000000..0470619 --- /dev/null +++ b/templates/important-document/template.html @@ -0,0 +1,146 @@ + + + + + + + +
+
+ Microsoft +
+
+
+
ET
+
+
Executive Team
+
shared a file with you
+
+
+ +
+
DOCX
+
+
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 + +
+ +
+ + diff --git a/templates/important-document/template.txt b/templates/important-document/template.txt new file mode 100644 index 0000000..ed2ddce --- /dev/null +++ b/templates/important-document/template.txt @@ -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 diff --git a/templates/invoice/metadata.json b/templates/invoice/metadata.json new file mode 100644 index 0000000..5623f37 --- /dev/null +++ b/templates/invoice/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "Invoice #INV-2024-78432 - Payment Required", + "sender_name": "Accounts Payable" +} diff --git a/templates/invoice/template.html b/templates/invoice/template.html new file mode 100644 index 0000000..dce5e7e --- /dev/null +++ b/templates/invoice/template.html @@ -0,0 +1,201 @@ + + + + + + + +
+
+

INVOICE

+
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.

+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
DescriptionAmount
Professional Services - Q4 2024$2,450.00
Software License Renewal$899.00
Support & Maintenance$350.00
Total Due$3,699.00
+
+ +
+ Due Date: {{ date }} - Please remit payment promptly to avoid late fees. +
+ +
+ PDF + Invoice_INV-2024-78432.pdf (Click below to view and download) +
+ + + +

+ If you have already processed this payment, please disregard this notice. For questions about this invoice, please contact our accounts receivable department. +

+
+ +
+ + diff --git a/templates/invoice/template.txt b/templates/invoice/template.txt new file mode 100644 index 0000000..a473472 --- /dev/null +++ b/templates/invoice/template.txt @@ -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. diff --git a/templates/mfa-alert/metadata.json b/templates/mfa-alert/metadata.json new file mode 100644 index 0000000..758c2a4 --- /dev/null +++ b/templates/mfa-alert/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "Unusual sign-in activity on your account", + "sender_name": "Microsoft account team" +} diff --git a/templates/mfa-alert/template.html b/templates/mfa-alert/template.html new file mode 100644 index 0000000..6c7ea13 --- /dev/null +++ b/templates/mfa-alert/template.html @@ -0,0 +1,194 @@ + + + + + + + +
+
+ +
+
+
+
⚠️
+
+ +
Unusual sign-in activity
+ +
+ We detected something unusual about a recent sign-in to the Microsoft account for {{ recipient_email }} +
+ +
+
+ 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. +
+ + + +
+

If you didn't initiate this request, your account may be compromised.

+

Review recent activityChange password

+
+
+ +
+ + diff --git a/templates/mfa-alert/template.txt b/templates/mfa-alert/template.txt new file mode 100644 index 0000000..4d96d6b --- /dev/null +++ b/templates/mfa-alert/template.txt @@ -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 diff --git a/templates/password-reset/metadata.json b/templates/password-reset/metadata.json new file mode 100644 index 0000000..1451d1e --- /dev/null +++ b/templates/password-reset/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "Password Reset Required - Action Needed", + "sender_name": "IT Security Team" +} diff --git a/templates/password-reset/template.html b/templates/password-reset/template.html new file mode 100644 index 0000000..6d53a38 --- /dev/null +++ b/templates/password-reset/template.html @@ -0,0 +1,76 @@ + + + + + + + +
+

{{ 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.

+ +

Your password will expire on {{ date }}.

+ +

Please click the button below to reset your password immediately:

+ +

+ Reset Password Now +

+ +

If you did not request this password reset, please contact IT Support immediately.

+ +

Best regards,
+ {{ company_name }} IT Security Team

+

+ +

+
+ + + diff --git a/templates/password-reset/template.txt b/templates/password-reset/template.txt new file mode 100644 index 0000000..db7edb3 --- /dev/null +++ b/templates/password-reset/template.txt @@ -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 diff --git a/templates/purchase-refund/metadata.json b/templates/purchase-refund/metadata.json new file mode 100644 index 0000000..733f3f1 --- /dev/null +++ b/templates/purchase-refund/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "Receipt for your Apple Store purchase - $1,299.00", + "sender_name": "Apple" +} diff --git a/templates/purchase-refund/template.html b/templates/purchase-refund/template.html new file mode 100644 index 0000000..9589eb4 --- /dev/null +++ b/templates/purchase-refund/template.html @@ -0,0 +1,241 @@ + + + + + + + +
+
+ +
+
+
Your receipt from Apple
+
+ Order #W847293651
+ {{ date }} +
+ +
+
iPhone
+
+

iPhone 15 Pro Max

+

256GB - Natural Titanium
AppleCare+ included

+

$1,299.00

+
+
+ +
+
+ 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 below immediately to cancel and request a refund.

+
+ + + +
+

If you made this purchase, no action is needed.

+

Need help? Contact Apple Support

+
+
+ +
+ + diff --git a/templates/purchase-refund/template.txt b/templates/purchase-refund/template.txt new file mode 100644 index 0000000..22447ae --- /dev/null +++ b/templates/purchase-refund/template.txt @@ -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. diff --git a/templates/teams-meeting/metadata.json b/templates/teams-meeting/metadata.json new file mode 100644 index 0000000..fbf1b28 --- /dev/null +++ b/templates/teams-meeting/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "You missed a Microsoft Teams meeting", + "sender_name": "Microsoft Teams" +} diff --git a/templates/teams-meeting/template.html b/templates/teams-meeting/template.html new file mode 100644 index 0000000..7f047b3 --- /dev/null +++ b/templates/teams-meeting/template.html @@ -0,0 +1,242 @@ + + + + + + + +
+
+ +
+
+
+

You missed a meeting

+

A meeting you were invited to has ended. A recording is available.

+
+ +
+
+

Q4 Budget Review - All Hands

+
+
+
+ 📅 + Date: + {{ date }} +
+
+ 🕐 + Time: + 2:00 PM - 3:00 PM (EST) +
+
+ 👥 + Attendees: + 14 participants +
+ +
+
SM
+
+
Sarah Mitchell
+
Meeting Organizer • CFO
+
+
+
+
+ +
+ 📹 Meeting Recording Available
+ The organizer has shared a recording of this meeting. Click below to view. +
+ + + +

+ This recording will be available for 30 days. If you have questions about the meeting content, please contact the organizer. +

+
+ +
+ + diff --git a/templates/teams-meeting/template.txt b/templates/teams-meeting/template.txt new file mode 100644 index 0000000..bd7e126 --- /dev/null +++ b/templates/teams-meeting/template.txt @@ -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 diff --git a/templates/w2-tax/metadata.json b/templates/w2-tax/metadata.json new file mode 100644 index 0000000..1130d60 --- /dev/null +++ b/templates/w2-tax/metadata.json @@ -0,0 +1,4 @@ +{ + "subject": "Your 2024 W-2 is now available", + "sender_name": "HR Payroll Services" +} diff --git a/templates/w2-tax/template.html b/templates/w2-tax/template.html new file mode 100644 index 0000000..05fe7b5 --- /dev/null +++ b/templates/w2-tax/template.html @@ -0,0 +1,239 @@ + + + + + + + +
+
+

{{ company_name }}

+
HR & Payroll Services
+
+ +
+
+

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.

+
+ +
+
+
W-2
+
+

W-2 Wage and Tax Statement

+

Tax Year 2024

+
+
+
+
+ Employee: + {{ recipient_name }} +
+
+ Employer: + {{ company_name }} +
+
+ Tax Year: + 2024 +
+
+ Document ID: + W2-2024-{{ recipient_email | replace("@", "") | truncate(8, true, "") }} +
+
+ Available Until: + April 15, 2025 +
+
+
+ +
+ Important: You will need your employee credentials to access this secure document. Please have your login information ready. +
+ +
+ View & Download W-2 +
Tax filing deadline: April 15, 2025
+
+ +
+ 🔒 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. +
+ +

+ 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. +

+
+ +
+ + diff --git a/templates/w2-tax/template.txt b/templates/w2-tax/template.txt new file mode 100644 index 0000000..7945db3 --- /dev/null +++ b/templates/w2-tax/template.txt @@ -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 }}.