=== My Newsletter ===
Contributors: georgijevic
Tags: newsletter, email newsletter, smtp, mailing list, email marketing
Requires at least: 5.8
Tested up to: 6.9
Requires PHP: 7.4
Stable tag: 2.6.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Send newsletters to users, commenters, or an imported mailing list (CSV/XLSX/paste) with SMTP, templates, queue sending, logs, and unsubscribe.

== Description ==

My Newsletter is a lightweight WordPress newsletter plugin focused on a practical use case many site owners need immediately:

* Send a campaign to WordPress users.
* Send a campaign to commenters (optionally only commenters from a specific post).
* Import and manage your own mailing list (CSV/TXT upload, simple XLSX upload, or paste emails).
* Queue the campaign and process it in the background (batch sending).
* Include unsubscribe links in every message.
* Track basic campaign progress in the admin area.
* Optional file logging for troubleshooting large sends.
* Optional built-in SMTP settings (with SMTP test) (no external SMTP plugin required).
* Save and load reusable email templates (v2.5.0).
* Manage templates (edit/rename/duplicate/delete) from My Newsletter → Templates (v2.6.0).
* Import/export templates as JSON for backup and migration (My Newsletter → Templates) (v2.6.1).

This plugin is intentionally simple and WordPress-native:

* Email sending uses `wp_mail()` (https://developer.wordpress.org/reference/functions/wp_mail/).
* Background processing uses WP-Cron (https://developer.wordpress.org/plugins/cron/).
* File uploads in the admin import flow use `wp_handle_upload()` (https://developer.wordpress.org/reference/functions/wp_handle_upload/).

= Mailing list import & management (v2.3.0) =

My Newsletter lets you import and manage your own subscriber list:

* Import subscribers via CSV/TXT upload, simple XLSX upload, or copy/paste.
* Preview the first rows before writing to the database.
* Choose merge behavior: Update existing or Skip existing.
* Built-in list tools: search, export CSV, delete selected, delete all matching search, and delete by domain.
* Suppression list (unsubscribed): view/export and remove suppression (admin-only).

Important: You are responsible for ensuring you have a lawful basis/consent to email imported contacts, and every campaign must include a working unsubscribe option.

Then, when composing a campaign, choose **Mailing list (imported)** as the recipient source.

= Core functionality =

* **Campaign composer (admin screen)**
  * Create a newsletter subject and HTML content.
  * Use the WordPress editor for message body content.
  * Choose recipient source:
    * Users + Commenters
    * Users only
    * Commenters only
    * Commenters on a specific post
    * Mailing list (imported)

* **Background queue processing**
  * Recipients are queued in custom plugin tables.
  * Sending runs in batches through WP-Cron (instead of trying to send everything in one browser request).
  * Reduces the risk of timeouts and broken sends on slower hosting.

* **Test email before full campaign**
  * Send a test message to any email address from the composer screen.
  * Uses the same rendering path and unsubscribe footer logic as real sends.

* **Secure unsubscribe links**
  * Every email includes an unsubscribe URL.
  * Unsubscribe tokens use an HMAC-based signature (derived from WordPress salts; see `wp_salt()` https://developer.wordpress.org/reference/functions/wp_salt/).
  * Unsubscribed addresses are stored and skipped in future campaigns.

* **Email templates (save/load) (v2.5.0)**
  * Save the current subject + content as a template.
  * Load a saved template into the composer to reuse it for a new campaign.
  * Templates are stored locally on your site (not sent anywhere).

* **Template variables (placeholders)**
  * `{{site_name}}`
  * `{{site_url}}`
  * `{{recipient_name}}`
  * `{{recipient_email}}`
  * `{{unsubscribe_url}}`

* **Settings screen**
  * From name
  * From email
  * Reply-To (optional)
  * Max emails per cron run (batch size)
  * Footer HTML (appended to outgoing emails)
  * Logging (optional)

* **Optional log file (v2.3.3)**
  * Enable logging in Settings → Logging.
  * View, download, and clear logs in **My Newsletter → Logs**.
  * Logs are stored in `wp-content/uploads/my-newsletter/wpnl.log`.

* **Basic campaign tracking**
  * Shows recent campaigns in admin.
  * Displays queue progress (total / sent / failed / queued).

== User Guide (v2.3.3) ==

= 1) Quick start (5–10 minutes) =

1. Install and activate the plugin.
2. Go to **My Newsletter → Settings** and set:
   * From name
   * From email (prefer an address on your domain)
3. Go to **My Newsletter** (campaign composer) and send a **Test email** to your own address first.
4. Create a campaign:
   * Enter Subject
   * Enter Message (HTML supported via the editor)
   * Choose recipients (Users / Commenters / Mailing list)
   * Click **Queue & Start Sending** (wording may vary by screen)

If you don’t see progress, read the “WP‑Cron” section below.


= 1B) Email templates (Save / Load) (v2.5.0) =

On the **My Newsletter** campaign screen you can reuse content without retyping:

1. Write your Subject and Content (or load an existing template).
2. To save: enter a template name and click **Save Email Template**.
3. To load: choose a template from the dropdown and click **Load Email Template**.

Tip: keep templates generic (e.g. “Welcome email”, “Promo template”), then adjust the final message before queuing.

= 1C) Manage Templates (v2.6.0) =

Use **My Newsletter → Templates** to manage your saved templates:

* **Add New** to create a template from scratch.
* **Edit** to update the template name (rename), subject, or body.
* **Duplicate** to quickly create a variation.
* **Delete** to remove a template you no longer need.

Templates are local to your site and can be loaded into the campaign composer using **Load Email Template**.

= 2) Settings explained (My Newsletter → Settings) =

* **From name / From email**  
  Used as the sender identity in outgoing messages. WordPress email is sent via `wp_mail()` and your mail transport decides the final headers (https://developer.wordpress.org/reference/functions/wp_mail/).

* **Reply‑To (optional)**  
  If you want replies to go to a different inbox than “From”.

* **Max emails per cron run (batch size)**  
  Limits how many emails each WP‑Cron run tries to send. Smaller batches reduce timeouts on shared hosting.  
  WP‑Cron is traffic-driven by default (https://developer.wordpress.org/plugins/cron/).

* **Footer HTML**  
  Appended to every message. Best practice is to include:
  * your site name,
  * a short reason why the recipient is receiving the email,
  * and an unsubscribe link (the plugin can insert `{{unsubscribe_url}}`).

* **Logging (optional, v2.3.3)**
  Enable logging when troubleshooting unexpected queue behavior or mail failures.

  1. Go to **My Newsletter → Settings → Logging** and enable the log file.
  2. Re-run sending (WP-Cron or “Run queue now”).
  3. Open **My Newsletter → Logs** to view, download, or clear the log.

  Logs are stored in `wp-content/uploads/my-newsletter/wpnl.log`.

= 3) Creating a campaign (My Newsletter → Campaigns) =

1. **Subject**: what recipients will see.
2. **Message body**: use the editor; HTML is allowed.
3. **Placeholders**: you can personalize using:
   * `{{recipient_name}}`, `{{recipient_email}}`
4. **Recipients**: choose one:
   * Users (WP users)
   * Commenters (emails from approved comments)
   * Commenters for a specific post
   * Mailing list (imported)

Then click the action button to queue recipients and start sending.

= 4) Recipient sources: what exactly is included =

* **Users**  
  Uses WordPress user emails (typically `wp_users.user_email`). WordPress user data is stored in core tables (https://developer.wordpress.org/apis/wpdb/).

* **Commenters**  
  Uses emails from comment records (typically `wp_comments.comment_author_email`) and only approved comments are considered in typical implementations (WordPress comment basics: https://developer.wordpress.org/reference/functions/get_comments/).

* **Commenters on a specific post**  
  Same as Commenters, but filtered by post ID.

* **Mailing list (imported)**  
  Uses subscribers stored by this plugin in its own table. This list is independent from WP users/comments.

= 5) Mailing list import (My Newsletter → Mailing List) =

You have two import methods: **Upload file** or **Paste**.

== 5A) Upload (CSV/TXT) ==

Best and most reliable method.

**Recommended columns**
* `email` (required)
* `name` (optional)

**CSV example**
email,name
ana@example.com,Ana
marko@example.com,Marko

The plugin will:
* accept comma/semicolon/tab-delimited CSV (delimiter auto-detected),
* accept a header row if it contains `email`,
* validate emails with WordPress helpers like `sanitize_email()` and `is_email()` (https://developer.wordpress.org/reference/functions/sanitize_email/ and https://developer.wordpress.org/reference/functions/is_email/),
* deduplicate by email during the import batch,
* skip emails that are already unsubscribed.

**Export from Excel / Google Sheets**
* Export to CSV. XLSX support exists, but CSV is safer for complex sheets.

== 5B) Upload (XLSX) ==

XLSX support is intentionally minimal to keep the plugin lightweight.

Requirements:
* First worksheet (sheet1)
* Column A = email
* Column B = name (optional)
* If cell A1 contains “email”, that row is treated as header and skipped

If your XLSX is more complex, export to CSV first.

== 5C) Paste emails (copy/paste) ==

Paste supports:
* one email per line,
* comma/semicolon separated emails,
* `Name <email@example.com>`,
* 2-column lines: `email,name` or `name,email` (comma/tab/semicolon).

Examples:
ana@example.com
marko@example.com,Marko
Ana Example <ana@example.com>
Marko Example <marko@example.com>

After import, the screen shows:
* imported count,
* invalid count,
* duplicate count,
* skipped unsubscribed count.


== 5D) Import workflow (Preview + merge rules) ==

1. Go to **My Newsletter → Mailing List**.
2. Upload a file (CSV/TXT/XLSX) or paste emails.
3. Click **Preview import**.
4. Confirm you have lawful basis/consent (required).
5. Choose merge behavior:
   * **Update existing (recommended):** update name/source/updated_at for existing emails.
   * **Skip existing:** only add new emails.
6. Click **Import now**.

After import, you can export and clean the list using:
* Export subscribers CSV,
* Delete selected (bulk),
* Delete all matching search,
* Delete by domain (e.g. `example.com`).

= 6) Viewing and managing the list =

In **My Newsletter → Mailing List**, you can:
* see the total subscriber count,
* search by email or name,
* browse paginated results,
* export subscribers as CSV,
* delete selected subscribers (bulk),
* delete all subscribers matching the current search (with confirmation),
* delete by domain (e.g. `example.com`) for quick cleanup.

In **Mailing List → Suppression list**, you can:
* view unsubscribed emails (suppressed),
* export suppression list as CSV,
* remove suppression (admin-only) if you need to re-subscribe someone manually.

= 7) WP‑Cron and reliable background sending =

This plugin uses WP‑Cron to send queued emails in batches. WP‑Cron runs on site visits (traffic).
On low‑traffic sites, campaigns may send slowly (https://developer.wordpress.org/plugins/cron/).

For reliable sending on production:
* Configure a real server cron to hit `wp-cron.php` at a fixed interval.
  WordPress explains this approach here: https://developer.wordpress.org/plugins/cron/#what-is-wp-cron.

Admin tools:
* In **My Newsletter → Settings**, use **Run queue now** (admin-only) to process one batch immediately for testing/troubleshooting.
* The Settings screen includes ready-to-copy cron examples (curl/wget) for common hosting setups.

= 8) Deliverability (what matters most) =

This plugin hands off email to WordPress via `wp_mail()` (https://developer.wordpress.org/reference/functions/wp_mail/).  
Deliverability depends on your mail transport and DNS.

If you care about inbox placement:
* Use an SMTP provider (or transactional email service).
* Use a sender on your own domain.
* Configure SPF/DKIM/DMARC (vendor-specific docs).

= 9) Compliance and consent (your responsibility) =

The plugin provides unsubscribe links, but it does not enforce consent or double opt‑in.  
You must only email people you have a lawful basis to contact and you must honor opt‑outs.

* FTC CAN‑SPAM overview: https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business
* EU GDPR overview (lawful basis, consent, etc.): https://commission.europa.eu/law/law-topic/data-protection/reform/what-does-general-data-protection-regulation-gdpr-govern_en

== Installation ==

= Standard WordPress upload (ZIP) =

1. In WordPress admin, go to **Plugins → Add New → Upload Plugin**.
2. Upload the plugin ZIP package.
3. Activate **My Newsletter**.
4. Go to **My Newsletter → Settings** and configure sender details.
5. Create your first campaign in **My Newsletter** and send a test email first.

= Manual installation =

1. Upload the `my-newsletter` folder to `/wp-content/plugins/`.
2. Activate the plugin in **Plugins**.
3. Configure settings and send a test email first.

== Frequently Asked Questions ==

= Does this plugin use double opt-in? =

Not yet. Version 2.1.0 focuses on admin-triggered newsletter sending, background queue processing, secure unsubscribe handling, and list importing.

= Why is my campaign sending slowly? =

Because WP-Cron is traffic based (https://developer.wordpress.org/plugins/cron/). If your site has little traffic, cron jobs run less frequently. Configure a real cron job for more reliable processing.

= Can I send to only commenters from one post? =

Yes. Choose **Commenters on a specific post** and select the post in the composer screen.

= Does it track opens/clicks? =

No. This plugin tracks send queue progress only (queued / sent / failed). It does not include analytics pixels or click tracking.

= Will unsubscribed addresses receive future campaigns? =

No. The plugin checks its unsubscribe table before queuing recipients.

= What if `wp_mail()` fails? =

Failed sends are marked as failed in the queue. For more reliable sending, configure SMTP and verify the sender domain (see `wp_mail()` docs: https://developer.wordpress.org/reference/functions/wp_mail/).

= What file should I upload for mailing list import? =

CSV is best. XLSX works only for simple two-column sheets (A=email, B=name). Paste import is good for quick lists.


= How do I import my mailing list? =
Go to **My Newsletter → Mailing List**. Upload CSV/TXT/XLSX or paste emails, then **Preview import** and choose the merge rule before importing.

= What happens if an email is already unsubscribed? =
Imported emails that are currently suppressed (unsubscribed) are skipped by design. You can review them in **Mailing List → Suppression list**.

= Can I export or delete subscribers in bulk? =
Yes. You can export subscribers as CSV, delete selected rows, delete all matching your current search, or delete by domain.
== Screenshots ==

1. Campaign composer screen
2. Settings screen
3. Campaign progress table
4. Mailing List screen (import + subscriber table)

== Changelog ==

= 2.6.1 =
* Added Templates JSON Import/Export (backup/migrate templates between sites) in My Newsletter → Templates.
* Updated plugin description and usage instructions for template library.

= 2.6.0 =
* Added Manage Templates submenu (My Newsletter → Templates): create, edit/rename, duplicate, and delete templates.
* Improved template workflow documentation (save/load + manage).

= 2.5.0 =
* Added email templates: Save Email Template + Load Email Template in the campaign composer.



= 2.4.1 =
* Added SMTP Test tool in Settings to send a test email and log the result.

= 2.4.0 =
* Built-in SMTP settings (Hostinger email compatible) so you can send newsletters without installing a separate SMTP plugin.
* Added Hostinger sending-limit guidance and recommended throttling notes on the Settings screen.
* Updated plugin description and documentation for mailing list import, SMTP, logging, and stop/resume controls.

= 2.3.6 =
* Optional SMTP settings (Host/Port/Encryption/Auth/Username/Password) built into My Newsletter (no external SMTP plugin required).
* Uses WordPress PHPMailer hooks; password field is not displayed and is only updated when you enter a new value.


= 2.3.5 =
* Fix: Stop/Resume campaign actions no longer trigger a fatal error; add proper admin-post and AJAX handlers.



= 2.3.4 =
* Added Stop/Resume controls for campaigns (pause sending without deleting queued emails)
* Queue processing skips stopped/paused campaigns and safely releases in-flight (sending) items

= 2.3.3 =
* Added optional log file (uploads/my-newsletter/wpnl.log) with Logs screen (view/download/clear)
* Added queue run locking and "sending" claim status to reduce duplicate processing when cron overlaps
* Added send attempt/success/failure log entries to help diagnose large sends

= 2.3.2 =
* Plugin Check fixes: filesystem handling via WP_Filesystem, CSV export without file handles, and SQL prepare improvements.

= 2.3.1 =
* Documentation update: clarified mailing list import & management in Description and User Guide
* Added step-by-step import workflow section (Preview + merge rules) and updated list management guidance
* Updated FAQs for import, suppression behavior, and bulk export/delete

= 2.3.0 =
* Added compliance UX in import preview (lawful basis / consent confirmation required)
* Added "Delete all matching search" (with confirmation) and "Delete by domain" tools for large lists
* Added Settings → Queue tools: "Run queue now" (admin-only) and Real cron setup examples

= 2.2.0 =
List management + suppression UI, plus import preview and merge rules.

= 2.1.0 =
* Added Mailing List screen with import via CSV/TXT upload, simple XLSX upload, and paste
* Added "Mailing list (imported)" as a campaign recipient source (queued directly from DB for performance)
* Added new list table (`wpnl_list`) with safe upsert and uninstall cleanup
* Added detailed User Guide section to readme for repository reviewers and end users

= 2.0.2 =
* Fixed remaining Plugin Check errors (escaping, discouraged functions, and `wp_parse_url()` compatibility)
* Added `languages` directory to satisfy plugin header `Domain Path`
* Updated readme metadata (`Tested up to`, tags) for repository review
* Cleaned uninstall routine variable prefixes and PHPCS annotations

= 2.0.1 =
* Plugin Check compatibility pass and cleanup
* Unified plugin text domain to `my-newsletter`
* Cleaned plugin header metadata
* Replaced anonymous PHP callbacks with named methods
* Moved textdomain loading to proper hook flow
* Hardened AJAX handlers (nonce verification, capability checks, input unslashing/sanitization)
* Improved PHPCS annotations for custom DB table queries and uninstall routine
* Added repository placeholder assets (icons/banners)
* Bundled improved readme documentation

= 2.0.0 =
* Modernized rewrite / rework of the plugin structure
* Added background queue processing and campaign composer


== Upgrade Notice ==

= 2.6.0 =
Manage saved email templates from a new Templates submenu (create/edit/rename/duplicate/delete).


= 2.4.1 =
SMTP Test tool added in Settings.

= 2.4.0 =
Built-in SMTP settings (smtp.hostinger.com compatible) and improved Settings guidance for Hostinger sending limits.

= 2.3.3 =
Optional file logging + safer queue processing (locking/claiming) for troubleshooting large sends.

= 2.3.2 =
Plugin Check fixes: improved filesystem/CSV export/SQL prepare handling.

= 2.2.0 =
List management + suppression UI, plus import preview and merge rules.

= 2.1.0 =
Mailing list import is now available (CSV/TXT, simple XLSX, or paste). You can now send campaigns to imported subscribers as a new recipient source.
