The From: address of an email can be forged (spoofing) — an allowlist alone is not sufficient protection for something that can email your whole membership. The required subject keyword adds a second check; keep it private and choose a non-obvious phrase. The keyword is stripped from the subject before delivery. This does not replace mailbox security or prevent an attacker who learns the keyword from sending a forged message. Audience & attachments Embed a code filter in the subject to target membership levels: Meeting notes [codes: GOLD,SILVER]. The tag is removed before delivery. Without a tag, the membership code filter saved on the Group Email page is applied; if that filter is blank, all members receive the message. Works on both main and chapter sites. Chapter sites send to the local chapter roster only — the code filter narrows within that roster, regardless of whether access checks also use the main roster. Email-in attachments are uploaded to the media library. With Pro's File Delivery link mode, every attachment becomes an expiring, recipient-bound link that opens without a login; PDFs may also be watermarked for the recipient. With link mode off, the first file is attached to site mail (or converted to a link if over 5 MB), while additional files use shared login-gated links. Mailchimp link mode supports up to five personalized file links per campaign; additional files are omitted with a notice. Accepted and permanently skipped authorized messages are marked read and recorded to avoid duplicate sends. Unauthorized or unrelated messages are ignored and left unread, with their IDs recorded so they are not repeatedly processed. Sales — sell memberships The Sales half of GSheet Membership puts a configurable buy-membership picker on any page and, on a successful payment, writes (or updates) the buyer's row in your private Google Sheet so they can immediately log in on your site. Three-dimensional picker — buyers choose Delivery (Electronic / Print / Both) × Duration (1-Year and Lifetime included by default; the Pro add-on adds custom levels and multi-year durations) × Postage (Regular, First Class, Canada/Mexico, Other International), and the price updates live as they change selections. Discrete pricing matrix — you set the exact price for every saleable combination in the admin. Enter 0 for a free membership that skips the gateway; leave a cell blank to make that combination unavailable. Stripe Checkout — the free plugin uses Connect with Stripe and hosted onboarding, with no API keys to paste; Pro can use your own Stripe keys instead. Card details stay on Stripe's hosted checkout page. Pro's own-key settings provide a Test/Live switch; free Connect has no separate mode switch in WordPress. PayPal Standard Checkout (requires the Pro add-on) — buyers can optionally pay via PayPal instead of (or in addition to) Stripe. Both gateways share the same sheet-upsert pipeline, purchase log, and retry UI. Sheet upsert — on a verified webhook the plugin first tries to update the row that matches the buyer's email; if there is no row, it appends one. Renewals extend an existing future expiration date instead of overwriting it. Reliable webhook pipeline — per-event and per-email atomic locks prevent duplicate writes from concurrent webhook redeliveries; a sheet-write failure returns HTTP 500 so Stripe retries, and the admin sees a notice. The Pro add-on adds an admin retry control for failed sheet writes. Buyer confirmation email — configurable subject and body with placeholders (first name, selection, amount, code, expiration, login URL, etc.). Integrations can enrich purchase variables with gsms_purchase_email_vars and adjust the rendered confirmation body with gsms_confirmation_body. Roster-aware checkout and contact collection — checkout distinguishes the signed-in purchaser's own verified email from another entered email or a gift recipient. Add-ons can collect contact fields independently of local sheet-write columns using the same field list for rendering and paid-checkout validation. With Chapters, this supports international State / Province / Region, Country, and Zone for main-organization reporting without local mappings. Electronic-delivery buyers can select the international-address checkbox when international fields are collected, even without a local ZIP column; administrator direct-apply still uses only local mappings. Admin direct-apply — a separate [gsms_admin_picker] shortcode lets a site administrator apply a membership directly to the sheet without taking a payment, perfect for comp memberships, cheque / cash-in-hand orders, or back-filling an old purchase. Membership Level Names — map the raw membership codes stored in your sheet to human-readable names, so a member who's denied access sees a name like "Gold Member" instead of the raw code. Pro adds a level editor; copying Pro levels to free-only storage requires an explicit administrator action. Requirements PHP 7.4+ with the standard openssl, hash, and mbstring extensions (already enabled on every major WordPress host). WordPress 5.9+. The access features (above) configured with a working Service Account — the sales pipeline reuses the same sheet-writer. A Stripe account for live or test payments (a PayPal developer account too, if you use the Pro add-on's PayPal checkout). Selling setup Configure the Access settings first (see Installation above) and confirm the Save & Test Main Roster button succeeds. Go to Membership Sales in the WordPress admin sidebar. Every sub-page shows a "Setup" notice at the top reminding you which shortcode to put on which page. Fill in the Pricing Matrix, Code Matrix, and Payments sub-pages (see Configuration below). Create a page containing only the shortcode [gsma_membership_purchase] — that is the buy page. Create (or pick) a thank-you page and put [gsma_user_info] on it (that shortcode shows the buyer's status with an inline login form when they're not yet signed in). Select that page on the Settings sub-page under Thank-you page. Shortcodes [gsma_login_form] — renders the sign-in form (email, then a first-time verification code or a returning password) on the page you choose as the Custom Login Page. Independent of the Sales feature — every site can use it. [gsma_membership_purchase] — renders the full picker (Delivery × Duration × Postage) with live total and the Buy membership button. Place this on the page where you want to take payments. [gsms_admin_picker] — admin-only variant of the picker that applies a membership directly to the sheet without any payment. Only site administrators (manage_options) see it; everyone else sees a polite notice. [gsma_user_info] — place it on the thank-you page so buyers see their membership status (and an inline login form when they aren't logged in). Admin sub-pages Pricing Matrix — one row per Delivery, one column per Postage, repeated for each Duration. Type a price into a cell to make it saleable, including 0 for a free membership; leave it blank to make that combination unavailable. The Membership Levels block above the grid lets you choose which levels are currently offered for purchase. Code Matrix — the membership code written into the buyer's sheet row for each combination. Every membership level gets its own row of codes. Levels beyond the built-in 1-Year and Lifetime, including multi-year durations, can be added with the Pro add-on; each new level gets its own Code Matrix row automatically. A warning is shown if any saleable cell is missing a code. Payments — enable Stripe and use Connect with Stripe in the free plugin (no API keys or Stripe webhook secret to paste). With Pro, use your own Stripe keys instead and optionally enable PayPal, which has its own credentials and webhook setup. General Settings (sidebar label Settings) — currency, thank-you page picker, optional override of the access settings' expiration column, annual new-member bonus cutoff, buyer confirmation email templates, and option labels. Recent Purchases — the last 200 purchase events with gateway and sheet status. Reconcile guides administrators through the original-payment, intended-membership and correction checks, with a shorter path for a completed full refund and a missing-record review when an entry is no longer retained. It records the verified outcome without charging, refunding or editing the roster, prevents another renewal from that payment, and clears the warning only when no unresolved failures remain. Pro adds an inline Retry form for failed sheet writes and refunds for supported purchases; refundable Stripe Connect sales can also be refunded in the free plugin. Configuration: webhooks Stripe Connect (free plugin): On the Payments page, click Connect with Stripe and complete Stripe's hosted onboarding. No Stripe API keys or direct webhook signing secret are entered in the free plugin; payment confirmations are relayed through the hosted Connect service. Direct Stripe API keys (Pro add-on only): If you choose Pro's own-key mode instead of Connect, configure separate Test/Live keys on the Payments page and register its direct webhook: Developers → Webhooks → Add endpoint. Paste the Stripe Webhook URL shown on the Pro Payments page (ends in /wp-json/gsma-sales/v1/stripe-webhook). Subscribe to a single event: checkout.session.completed. Copy the resulting Signing secret (whsec_...) into Pro's matching webhook field for that mode. PayPal (requires the Pro add-on): In the PayPal developer dashboard → My Apps & Credentials → your app → Add webhook. Paste the PayPal Webhook URL shown on the plugin's Payments page (ends in /wp-json/gsma-sales/v1/paypal-webhook). Subscribe to CHECKOUT.ORDER.APPROVED and PAYMENT.CAPTURE.COMPLETED. Copy the resulting Webhook ID into the matching field on the plugin's Payments page.