En vous promenant sur Beamreactor, nous stockons votre IP 48h pour des raisons de sécurité.

Lecteur Markdown

newsletter Documentation › NEWSLETTER_DOCUMENTATION

NEWSLETTER_DOCUMENTATION

XDP Plugin: Newsletter #

Plugin: `newsletter.php`

Version: 2.1.0

Since: 2004

Last updated: 2025-12-26

Author: Treveur Bretaudière

License: Proprietary

---

Overview #

Batch newsletter sending system with text and HTML support, WYSIWYG editor, configurable batch sending, per-recipient tracking, and dual-audience subscriber management (registered users + visitor subscriptions). Operates in two modes: admin interface for creation/sending, and public subscribe/unsubscribe form for embedding in pages.

Files #

| File | Role |

|---|---|

| `newsletter.php` | Main plugin — admin interface + embedded public form |

| `newsletter_subscribe.php` | Standalone subscription form |

| `newsletter_send.mod.php` | Scheduler module for automated batch sending (JSON API) |

| `newsletter.conf.inc.php` | Configuration (batch size, access level) |

| `newsletter_en_inc.php` | English locale |

| `newsletter_fr_inc.php` | French locale |

| `newsletter.sql` | Table creation script |

Database #

Table: `newsletter` #

| Column | Type | Description |

|---|---|---|

| `id` | INT (PK) | Auto-increment |

| `user_id` | INT | Creator user ID |

| `subject` | VARCHAR(998) | Email subject (RFC 2822: 1000 octets max, -2 for CRLF) |

| `body_text` | TEXT | Plain text content (or HTML fallback) |

| `newsletter_html` | TEXT | HTML content |

| `format` | ENUM | `text` or `html` |

| `status` | ENUM | `draft`, `queued`, `sending`, `sent`, `failed` |

| `total_recipients` | INT | Total recipient count |

| `sent_count` | INT | Successfully sent counter |

| `created_at` | DATETIME | Creation timestamp |

| `sent_at` | DATETIME | Completion timestamp (NULL if in progress) |

Table: `newsletter_recipients` #

| Column | Type | Description |

|---|---|---|

| `id` | INT (PK) | Auto-increment |

| `newsletter_id` | INT | FK → `newsletter.id` (CASCADE delete) |

| `user_id` | INT | User ID (0 for visitor subscribers) |

| `email` | VARCHAR(255) | Recipient email |

| `status` | ENUM | `pending`, `sent`, `failed` |

| `sent_at` | DATETIME | Sent timestamp |

| `error_message` | TEXT | Error details on failure |

Table: `newsletter_subscription` #

| Column | Type | Description |

|---|---|---|

| `id` | INT (PK) | Auto-increment |

| `email` | VARCHAR(255) | Visitor email (UNIQUE) |

| `subscribed_at` | DATETIME | Subscription timestamp |

Stores non-registered visitor subscriptions. Registered users use the `email_bot` flag in the main user table instead.

Security Model #

| Level | Constant | Capabilities |

|---|---|---|

| Moderator | `NEWSLETTER_LEVEL_MODERATOR` | Create, preview, queue, send newsletters |

| Scheduler module | `NEWSLETTER_LEVEL_MODERATOR` | Trigger batch sending via cron |

Public form (subscribe/unsubscribe) requires no authentication.

Sanitization #

Subject: `Parser::sanitize(..., 'string', [], 998)` — max 998 chars per RFC 2822.

Body text: `Parser::sanitize(..., 'string', [['WORDWRAP' => 75]], 65535)` — standard email line width + MySQL TEXT limit.

HTML body: `Parser::sanitize(..., 'html', ['moderator'], 65535)` — tag filtering (script, iframe, etc.).

Subject encoding: `=?UTF-8?B?...?=` per RFC 2047 for non-ASCII characters.

Architecture #

Dual-mode Operation #

Admin interface (`$obj == 'newsletter.php'`): creation, preview, queue, batch send, history. Requires `NEWSLETTER_LEVEL_MODERATOR`.

Public form (`$obj != 'newsletter.php'` or via `newsletter_subscribe.php`): toggle subscribe/unsubscribe widget, embeddable in any page. No authentication required.

Subscriber Sources #

Newsletter recipients are aggregated from two sources at queue time:

1. Registered users: `SELECT FROM {$cfg['dbtable']} WHERE email_bot='1' AND activated='1'`

2. Visitor subscriptions: `SELECT FROM newsletter_subscription` — with deduplication against registered users (visitors already in the user table are removed from `newsletter_subscription` and not double-counted)

Data Flow #

Registered users → {$cfg['dbtable']}.email_bot ('0'/'1')
Visitor subscribers → newsletter_subscription.email
					↓
			  queueNewsletter()
			  [deduplication + merge]
					↓
		  newsletter_recipients (status='pending')
					↓
			 sendBatch() ×N
					↓
		newsletter.status='sent'

Actions #

list (default) #

URL: `?obj=newsletter.php`

Displays table of all newsletters with subject (clickable), creator username, status badge, recipient count, sent count with percentage, and creation date. "Create newsletter" button links to the create form.

create #

URL: `?obj=newsletter.php&action=create`

Form fields: subject (max 998 chars, required), format toggle (text/html radio), text textarea (20×80) or RTE HTML editor (800×400, full toolbar with source toggle). Displays active subscriber count. Blocks creation if zero subscribers. Submits to `action=preview`.

preview #

URL: `?obj=newsletter.php&action=preview` (POST)

Validates subject and body. For HTML format, generates a plain text fallback via `strip_tags()` with 75-column wordwrap. Displays the preview with buttons to queue, edit, or cancel.

queue #

URL: `?obj=newsletter.php&action=queue` (POST)

Inserts the newsletter record, retrieves all subscribers (registered + visitors), deduplicates visitor entries against the user table, and inserts all recipients as `status='pending'`. Displays confirmation with recipient count and link to start sending.

send_batch #

URL: `?obj=newsletter.php&action=send_batch&id={id}`

Fetches next batch of pending recipients (default 50, configurable via `NEWSLETTER_BATCH_SIZE`). Constructs MIME headers, sends via `mail()`, tracks per-recipient success/failure. Displays sent/failed/remaining counts. If remaining > 0, offers "Send next batch" button. When complete, sets newsletter status to `sent`.

view #

URL: `?obj=newsletter.php&action=view&id={id}`

Read-only view of a newsletter: subject, creator, status, recipient/sent counts, dates, and content preview (HTML rendered + text fallback, or plain text).

Email Format #

Plain text: `Content-Type: text/plain; charset=UTF-8; format="flowed"` — single-part.

HTML: `Content-Type: multipart/alternative` with MIME boundary `BeamReactor_{website}_{uniqid}`. Contains text/plain fallback part followed by text/html part. Ensures clients without HTML rendering receive a readable version.

From: `$cfg[11]['noreply']` (priority) or `$cfg[10]` (fallback).

X-Mailer: `BeamReactor/2.0`

Scheduler Module #

`newsletter_send.mod.php` provides a JSON API endpoint for automated batch sending, intended for cron job integration:

*/5 * * * * curl -s "https://example.com/?mod=newsletter_send"

If no specific newsletter ID is provided, it picks the oldest `queued` or `sending` newsletter. Returns JSON with `success`, `sent`, `failed`, `remaining`, and `status` fields.

Subscribe / Unsubscribe #

Toggle mechanism: same form, same action. If the email is already subscribed, it unsubscribes. If not, it subscribes.

Registered users: toggles `email_bot` field (`'0'`/`'1'`) in the user table.

Visitors: INSERT into / DELETE from `newsletter_subscription`.

Available as embedded form (when `newsletter.php` is included with `$obj != 'newsletter.php'`) or as standalone plugin (`newsletter_subscribe.php`).

Configuration #

| Variable | Usage | Default |

|---|---|---|

| `NEWSLETTER_BATCH_SIZE` | Emails per batch | 50 |

| `$cfg[10]` | Default sender email | — |

| `$cfg[11]['noreply']` | Noreply email (priority) | — |

| `$cfg['dbtable']` | User accounts table | — |

| `$charset` | Email charset | `UTF-8` |

| `$website` | Site name (MIME boundary) | — |

| `$basedisplevel` | Config access level | `BASE_LEVEL_MODERATOR` |

Locale #

File: `getlocale('newsletter')` — Variable: `$dialnewsletter[]`

| Range | Content |

|---|---|

| 0–8 | Validation errors, sending feedback |

| 9–18 | List view labels, subscriber count |

| 19–27 | Create/edit form labels |

| 28–38 | Queue and batch sending messages |

| 39–41 | Detail view labels |

| 60–67 | Subscribe/unsubscribe form |

Dependencies #

  • `Beamreactor\Database\SQL` — prepared statements
  • `Beamreactor\Sanitizer\Parser` — input validation
  • `frameheader()` / `framefooter()` — frame system
  • `secure()` — permission checks
  • `forbids()` — access denied handler
  • `rte-modern.js` — WYSIWYG editor
  • `mail()` — PHP native mail function

Configuration Reference #

| Config | Usage |

|---|---|

| `$cfg[0]` | Site base URL |

| `$cfg[10]` | Default sender email |

| `$cfg[11]['noreply']` | Noreply email address |

| `$cfg[17]` | Max file upload size |

| `$cfg['dbtable']` | User accounts table name |

de en fr