Author: onetwothreeadmin

  • WordPress transactional email: SMTP vs. API and when each fails

    WordPress transactional email: SMTP vs. API and when each fails

    WordPress transactional email: SMTP vs. API and when each fails
    Photo by Philip Oroni on Unsplash

    WordPress sends two kinds of email: the newsletters and marketing messages you schedule through a platform, and the transactional messages your site generates automatically—password resets, comment notifications, form submissions, order confirmations. Most operators notice the latter only when it breaks.

    Transactional email typically leaves your server through one of two methods: SMTP (Simple Mail Transfer Protocol) or API. Each has different failure modes, and mixing them up costs you customer trust and support time.

    SMTP: the older, slower, more fragile path

    SMTP is the internet’s original email-sending protocol, defined in RFC 5321 (checked October 2026). When WordPress uses SMTP, it opens a connection to a mail server, authenticates, hands over the message, and waits for confirmation. Plugins like WP Mail SMTP and Easy WP SMTP reconfigure WordPress to route outbound mail through a dedicated SMTP service instead of your web host’s default mail server.

    SMTP works, but it’s synchronous: WordPress waits for the handshake to complete before moving on. If the remote server is slow or the connection times out, your user sees a spinning loader or an error. Shared hosting providers often throttle or block port 25 (the default SMTP port) to prevent spam, forcing you to use port 587 or 465 with TLS authentication. Firewall rules, IP reputation scores, and greylisting all introduce points of failure.

    When SMTP fails, the symptom is usually silence—no error logged, no email delivered, no bounce notification. WordPress assumes the handoff succeeded because the SMTP server accepted the connection, but downstream filters or reputation blocks kill the message before it reaches the inbox.

    API: faster, more observable, purpose-built for transactional mail

    API-based transactional email services—Postmark, SendGrid, Amazon SES, Mailgun—let WordPress send a JSON payload over HTTPS instead of negotiating an SMTP handshake. The request completes in milliseconds, returns a message ID, and hands off delivery to infrastructure purpose-built for high-volume transactional sending.

    API transport is asynchronous by design. WordPress fires the request and moves on; the service handles queuing, retries, and reputation management. You get webhooks for bounces, complaints, and delivery events, and a dashboard that shows exactly which messages were sent, opened, or blocked. When an API call fails, you see an HTTP status code and an error message—usually authentication errors, rate limits, or malformed payloads.

    The trade-off: API services require a plugin (or custom code) to replace WordPress’s default wp_mail() function. You’re also introducing a dependency on a third-party service. If their API goes down or your authentication token expires, transactional mail stops until you fix it. SMTP plugins can fall back to the host’s mail server; API plugins typically can’t.

    When each method breaks—and how to tell

    SMTP failures are usually silent and network-layer: port blocks, authentication mismatches, IP reputation issues, SPF or DKIM misconfigurations. You’ll see timeouts in server logs, but WordPress itself often reports success. Tools like MXToolbox (checked October 2026) help you test DNS records and mail-server reachability from outside your hosting environment.

    API failures are louder and application-layer: invalid API keys, exceeded rate limits, rejected sender domains, webhook signature mismatches. Check your plugin’s debug log and the service’s activity dashboard. Most API providers offer a test-send endpoint you can call from the plugin settings to verify the integration before a customer triggers a real message.

    For high-stakes transactional email—password resets, two-factor codes, order confirmations—API transport is the safer default. Postmark, for example, focuses exclusively on transactional delivery and publishes a real-time deliverability dashboard (checked October 2026). Services that blend marketing and transactional sending (SendGrid, Mailgun) require careful IP-pool and subdomain configuration to keep reputation clean.

    Pick the method that matches your failure budget

    If your site sends fewer than a hundred transactional emails a month and you’re comfortable diagnosing SMTP authentication in cPanel, a basic SMTP plugin works. If missed password resets cost you support hours or revenue, route transactional mail through a dedicated API service and set up a separate monitoring ping for delivery rate.

    Don’t rely on your web host’s default mail server for anything that matters. Shared hosting mail has no reputation management, no bounce handling, and no visibility. The five dollars a month you save by skipping a dedicated transactional service costs you more the first time a customer’s order confirmation lands in spam.

    Want more infrastructure deep-dives like this? Subscribe to One Two Three Send and get one operator-focused article every morning.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • Social media platforms remove links differently—what survives

    Social media platforms remove links differently—what survives

    Social media platforms remove links differently—what survives
    Photo by Julian on Unsplash

    Post the same link across four platforms and you’ll see four different outcomes. LinkedIn will render a preview card. X might throttle your reach. Threads will bury you in the algorithm. Bluesky leaves it alone but offers no preview. None of this is documented well, and most operators only notice when traffic drops.

    Understanding how each network treats external URLs—and why—helps you route traffic without fighting the platform. Here’s what happens to your links on the four networks solo operators use most in 2026.

    LinkedIn: preview cards stay, but the algorithm favours native content

    LinkedIn renders link previews automatically when you paste a URL into a post. The card shows the page title, description, and featured image pulled from your Open Graph tags. That part works reliably.

    What LinkedIn doesn’t advertise: posts with external links receive less algorithmic distribution than text-only posts or native document uploads. LinkedIn’s creator guidance (checked October 2026) encourages members to “start conversations” rather than drive clicks away from the platform.

    Operators who post the same article as a LinkedIn native document—uploaded as a PDF or composed in LinkedIn’s article editor—report higher impression counts than link posts. LinkedIn doesn’t publish the discount rate, but the pattern is consistent enough that most B2B newsletters now post a teaser on LinkedIn and put the link in the first comment instead of the original post body.

    That workaround still triggers a preview card in the comment thread, and anecdotally performs better than embedding the link in the main post. LinkedIn has not confirmed this behaviour, but it aligns with their stated preference for on-platform engagement.

    X: external links trigger reach throttling

    X (formerly Twitter) has publicly stated that posts containing external links receive less distribution. In April 2023, Elon Musk posted that the platform would “vastly increase” the weight of text and media shared natively versus links that take users off-site. That policy remains in effect as of October 2026.

    When you include a URL in a post on X, the platform renders a preview card with the title, description, and image. But the post’s reach—measured by impressions and profile visits—drops compared to identical text posted without a link.

    The recommended workaround: post your commentary or hook as the main tweet, then reply to your own tweet with the link. The reply still gets seen by your followers and appears in the thread, but the primary post enters the algorithm without the external-link penalty. This two-tweet pattern is now standard among newsletter operators and content creators who rely on X for traffic.

    One edge case: X prioritises posts from paid subscribers (X Premium, formerly Blue). Paid accounts see less severe throttling on link posts, though the gap still exists. X Premium features (checked October 2026) mention “higher ranking in conversations and search” but do not quantify the link-post discount.

    Threads: links work, but discovery is nearly invisible

    Threads, Meta’s text-based social network, allows external links and renders basic preview cards when you paste a URL. The post appears in your followers’ feeds. But Threads’ recommendation algorithm—the “For You” feed that drives most discovery—heavily favours conversational posts over promotional content.

    Meta has not published detailed ranking criteria for Threads, but the launch announcement (July 2023) emphasised “positive, productive conversations.” In practice, posts with external links rarely appear in the For You feed unless they’ve already generated significant replies and engagement from your direct followers.

    Threads also lacks hashtag search and keyword discovery as of October 2026, so there’s no SEO-style workaround. The platform functions best as a discussion space for your existing audience, not a traffic engine. Operators who treat Threads as a place to build relationships—then move readers to a newsletter or blog via profile bio link—see better results than those who post links directly.

    Bluesky: links are untouched, but previews require extra work

    Bluesky does not penalise external links in its algorithm. The platform’s federation protocol (checked October 2026) treats links as plain text by default. If you want a preview card, you need to ensure your page includes valid Open Graph meta tags (og:title, og:description, og:image).

    Bluesky fetches these tags when you paste a URL, but the process is less forgiving than LinkedIn or X. If your image is too large (over 1 MB), not served over HTTPS, or missing a proper content-type header, the preview fails silently and your link appears as plain blue text.

    The upside: Bluesky’s chronological and discovery feeds don’t down-rank link posts. If your audience follows you, they see your posts in order. The lack of algorithmic suppression makes Bluesky one of the cleanest platforms for driving traffic, provided your audience is already there.

    What this means for your posting strategy

    If you’re sending readers to a newsletter signup page, a blog post, or a product launch, the platform you choose matters as much as the copy.

    • LinkedIn: Post a text teaser or native document; drop the link in the first comment.
    • X: Post the hook as the main tweet, reply with the link immediately.
    • Threads: Use it for conversation and community; put the destination link in your profile.
    • Bluesky: Post the link directly; make sure your Open Graph tags are clean.

    Each network’s link policy reflects its business model. Platforms that monetise attention (LinkedIn, X, Threads) want users to stay on-platform. Bluesky, built on open protocols and funded by grants rather than ads, has no such incentive—yet.

    If you’re using a scheduler like Publer to post across networks, don’t syndicate identical link posts. Customise the format for each platform, or accept that some networks will suppress your reach. The same URL posted four ways will perform four times differently.

    Got a question about cross-posting or social traffic? Reply to this email—we read every response and use your questions to shape future articles.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • WordPress database table indexes: where queries slow down and how to check

    WordPress database table indexes: where queries slow down and how to check

    WordPress database table indexes: where queries slow down and how to check
    Photo by Rahul Mishra on Unsplash

    Your WordPress site feels slow. You’ve already compressed images, minified CSS, enabled object caching—and page load times are still terrible. The culprit is often hiding in plain sight: database table indexes that are missing, bloated, or broken.

    Most solo operators never look at their database structure until something breaks. But queries that scan hundreds of thousands of rows without an index can add seconds to page generation time, even on small sites. Here’s how to find the problem tables and decide what to do about them.

    What indexes do and why they break

    An index is a sorted lookup table that helps MySQL find rows without scanning the entire table. When WordPress runs a query like SELECT * FROM wp_posts WHERE post_status = 'publish' ORDER BY post_date DESC, MySQL checks for an index on post_status and post_date. If those indexes exist, the query returns in milliseconds. Without them, MySQL reads every row in the table—thousands or millions of disk operations.

    Indexes break or go missing for a few reasons:

    • Plugin migrations that create custom tables without proper indexes
    • Large DELETE operations that leave fragmented indexes behind
    • Manual SQL imports that skip index definitions
    • Composite indexes that don’t match the query’s WHERE clauses

    The WordPress core tables—wp_posts, wp_postmeta, wp_options, wp_comments—ship with solid default indexes (WordPress Codex database schema reference, checked October 2026). But plugins that add metadata, log tables, or custom post types often don’t add indexes for their own queries.

    How to identify slow queries and missing indexes

    Start by enabling MySQL’s slow query log. Most managed WordPress hosts (including BigScoots) expose this in their dashboard or phpMyAdmin. If you run your own server, add these lines to my.cnf or my.ini:

    slow_query_log = 1
    slow_query_log_file = /var/log/mysql/slow-query.log
    long_query_time = 1

    Any query taking longer than one second will be logged. Restart MySQL, let your site run under normal traffic for an hour, then open the log. Look for queries with high Rows_examined counts—anything above 10,000 rows for a single SELECT is a red flag.

    Next, check which tables are missing indexes. Log into phpMyAdmin or your database client, select your WordPress database, and run:

    SHOW TABLE STATUS;

    Look at the Data_length and Index_length columns. If a table has 50 MB of data but only 2 MB of indexes, and you know plugins are querying it heavily, you likely need to add indexes.

    To see which indexes exist on a specific table, run:

    SHOW INDEX FROM wp_postmeta;

    WordPress adds a post_id index and a meta_key index by default. If a plugin queries WHERE meta_key = 'custom_field' AND meta_value = 'something', and there’s no composite index on (meta_key, meta_value), that query will be slow.

    When to add an index and when to leave it alone

    Adding an index speeds up reads but slows down writes. Every INSERT, UPDATE, or DELETE has to rebuild the affected indexes. For tables that change constantly—like wp_options with autoloaded data—a poorly chosen index can make things worse.

    Add an index if:

    • The slow query log shows repeated queries scanning tens of thousands of rows
    • The table is read-heavy (e.g., custom post type archives, metadata lookups)
    • The query filters or sorts on a column that isn’t indexed

    Skip the index if:

    • The table has fewer than 1,000 rows (the overhead isn’t worth it)
    • The column has very low cardinality (e.g., a boolean field with only two values)
    • Write performance matters more than read performance (e.g., logging tables)

    To add a single-column index:

    ALTER TABLE wp_postmeta ADD INDEX meta_value_idx (meta_value(191));

    The (191) limits the indexed portion of the column to 191 characters, which keeps the index size manageable for utf8mb4 collation (MySQL CREATE INDEX documentation, checked October 2026).

    For composite indexes matching a specific query pattern:

    ALTER TABLE wp_postmeta ADD INDEX meta_key_value_idx (meta_key, meta_value(191));

    The non-obvious tip: rebuild fragmented indexes quarterly

    Even well-indexed tables degrade over time. If you run a membership site, a course platform, or any WordPress install with heavy comment or metadata churn, indexes become fragmented. MySQL has to read more disk blocks to traverse the index tree, and queries slow down even though the index exists.

    Check fragmentation by running:

    SHOW TABLE STATUS LIKE 'wp_postmeta';

    Look at the Data_free column. If it’s more than 20% of Data_length, the table is fragmented. Rebuild it with:

    OPTIMIZE TABLE wp_postmeta;

    This locks the table briefly (usually seconds for tables under 1 GB), so run it during low-traffic windows. Set a calendar reminder to OPTIMIZE your largest tables every quarter. On a site with 50,000 posts and heavy metadata, this alone can cut query times in half.

    Want more infrastructure deep-dives like this? Subscribe to One Two Three Send—every article is written for operators who want to understand the layer below the dashboard.

  • Most solo operators track the wrong email metric first

    Most solo operators track the wrong email metric first

    Most solo operators track the wrong email metric first
    Photo by Samuel Bourke on Unsplash

    When you launch your first newsletter, every platform dashboard puts open rate front and centre. It’s big, it’s visible, and it feels like the number that matters. Click-through rate sits right next to it. Both feel urgent—how many people opened, how many clicked.

    But neither metric tells you whether your email reached the inbox in the first place.

    Delivery rate—the percentage of sent emails that were accepted by the recipient’s mail server—is the first number you should check every time you send. If your delivery rate drops, nothing else matters. Your brilliant subject line, your perfect call-to-action, your segmented list: all invisible if the email bounced or never left the queue.

    What delivery rate actually measures

    Delivery rate counts how many emails were accepted by the receiving server. It does not tell you whether the email landed in the inbox, the promotions tab, or the spam folder—only that the server didn’t reject it outright.

    Most email platforms calculate it as: (total sent − bounces) ÷ total sent. A hard bounce (invalid address, domain doesn’t exist) counts against you. A soft bounce (mailbox full, temporary server issue) may retry, but repeated soft bounces eventually become hard bounces.

    According to Postmark’s email deliverability guide (checked October 2026), a healthy delivery rate sits above 95%. Below that, you have list-hygiene problems, authentication issues, or you’re hitting spam traps.

    Why it breaks before open rate does

    Open rate can look fine even when your delivery infrastructure is failing. Here’s how: if 100 emails bounce but 400 reach the inbox and 80 of those open, your open rate is 20%—reasonable on paper. But your delivery rate is 80%, which means one in five emails never arrived.

    Platforms like Beehiiv and MailerLite surface delivery rate in their analytics dashboards, but it’s often tucked below the fold or inside a secondary report. You have to choose to look at it. Open rate and click rate update live; delivery rate might only refresh after the send completes, so it feels less immediate.

    The gap widens when you clean your list based on engagement. You remove subscribers who haven’t opened in 90 days, and your open rate climbs. But if those subscribers were valid addresses—just disengaged—you’ve done nothing to fix the bounces that hurt your sender reputation. Delivery rate would have told you the real problem.

    When to investigate a drop

    Check delivery rate after every send, especially if you’ve changed list sources, import methods, or authentication records. A drop of more than 2–3% between sends means something structural shifted.

    Common causes: you imported a purchased or scraped list (don’t), your SPF or DKIM records broke during a DNS migration, your sending domain was flagged by a blocklist, or your platform’s shared IP pool got penalised by another sender.

    Most platforms let you export bounces with reason codes. RFC 3463 defines the standard SMTP status codes: 5.x.x codes are permanent (hard bounce), 4.x.x are temporary (soft bounce). If you see a surge in 5.1.1 (user unknown) or 5.1.2 (domain not found), your list quality collapsed. If you see 4.2.2 (mailbox full) or 4.4.1 (connection timeout), it’s usually transient—but watch for patterns.

    What to do when delivery rate falls

    First: segment your most recent import or sign-up cohort and check its delivery rate separately. If new subscribers bounce at 15% but your core list delivers at 98%, the problem is your acquisition source, not your infrastructure.

    Second: verify your email authentication. Google’s DMARC, DKIM, and SPF setup guide (checked October 2026) walks through the DNS records every sender needs. If you migrated hosting or changed your sending service, these records may have been orphaned or overwritten.

    Third: remove hard bounces immediately. Every platform auto-suppresses them, but if you’re exporting lists between tools or using a secondary CRM, you may be re-importing dead addresses. One send to a known-bad address can trigger spam-trap alerts.

    Fourth: if delivery rate is healthy but inbox placement feels low (opens are down but bounces aren’t up), you’re likely landing in spam or promotions. That’s a separate problem—content, sending frequency, and engagement history—but delivery rate rules it out as a DNS or list-quality issue.

    Here’s the workflow: Before you obsess over subject-line A/B tests or click-map heatmaps, make delivery rate your first dashboard check. Set a threshold—95% minimum—and investigate any send that falls below it. Fix authentication, clean your list, and isolate bad acquisition sources. Only then does open rate tell you anything useful.

    If you want to dig deeper into email infrastructure and why some platforms handle bounces better than others, reply and let us know—we’ll compare how Postmark, MailerLite, and Beehiiv surface delivery diagnostics in a future piece.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • Google Search Console filters break when you stack more than five

    Google Search Console lets you stack filters to drill into your traffic. Want to see queries for a specific page that triggered featured snippets in France on mobile? You can add a filter for each dimension.

    Except when you hit the wall—and GSC doesn’t tell you when you do.

    The five-filter threshold

    Google Search Console supports up to five active filters in the Performance report at once. Add a sixth, and the interface doesn’t stop you. It accepts the input, renders the table, and shows numbers. But your export will be incomplete.

    The Search Console Help documentation (checked October 2026) doesn’t call out a hard limit on the filter count. The behavior surfaces only when operators export filtered data to Sheets or CSV and notice row counts don’t match the interface preview.

    Why five? The API endpoint underlying both the web UI and the Search Console API accepts a dimensionFilterGroups array, and while Google’s documentation doesn’t enumerate a maximum array length, empirical testing by SEO tooling vendors has consistently surfaced failures or incomplete results past five simultaneous dimension filters.

    What breaks when you go over

    When you stack six or more filters, the web interface may render a preview table. Clicks, impressions, CTR, and position numbers appear. The problem shows up on export: row counts drop, edge-case queries vanish, and aggregated totals no longer reconcile with the unfiltered view.

    If you’re filtering by page, query, country, device, and search appearance type—then add a date range as a sixth dimension filter—your export will silently omit rows that match all criteria. The interface won’t throw an error. The download completes. You’ll only catch the gap if you cross-check row counts or notice missing queries you know triggered impressions.

    This isn’t a recent regression. The five-filter behavior has persisted across multiple GSC interface updates since at least late 2024, and Google has not documented or acknowledged it as a known limitation in public help articles.

    How to work around it

    The most reliable method: reduce your filter count to five or fewer, then segment your export into multiple pulls.

    Say you want queries for a specific page, filtered by country, device, and two search appearance types. That’s five filters. If you also need to break out results by date, export the full five-filter dataset first, then pivot or filter by date in your spreadsheet tool after download.

    Alternatively, use the Search Console API directly and run multiple requests with different filter combinations, merging results in your own database or script. The API accepts the same dimensionFilterGroups structure, so the five-filter ceiling persists—but you control the aggregation logic and can validate row counts across batches.

    If you’re pulling GSC data into a BI tool or automated report, hard-code your filter count check. Any workflow that programmatically applies filters from user input should cap the array length at five and surface a warning when a user tries to add more.

    When you actually need more than five

    Most operator queries don’t require six filters. If you’re stacking that many, you’re often conflating segmentation (which belongs in post-export analysis) with filtering (which limits the raw dataset).

    Example: instead of filtering by page + query + country + device + search appearance + date range, filter by page + country + device, export the full dataset, then use spreadsheet pivot tables or a SQL query to slice by search appearance and date. You’ll get complete data and more flexibility to shift dimensions without re-running exports.

    For operators who need repeatable, complex segmentation, consider logging GSC API responses to a local database daily. Tools like Google’s Python API client make it straightforward to schedule nightly pulls of unfiltered Performance data, which you then query locally without filter-count limits.

    One last thing: if you’ve found a GSC filter or export behavior that doesn’t match what’s documented, reply and tell us. We track these gaps and update when Google changes the ceiling—or finally documents it.

    Want walkthroughs like this in your inbox? Subscribe to One Two Three Send—one operator-focused article every day.

  • WordPress comment moderation queues: how filters decide what lands where

    WordPress comment moderation queues: how filters decide what lands where

    WordPress comment moderation queues: how filters decide what lands where
    Photo: Piotrus via Wikimedia Commons (CC0)

    WordPress comment moderation is a black box until you dig into the settings. A first-time visitor leaves a thoughtful reply and it vanishes into the moderation queue. A known commenter posts a link and gets flagged as spam. The system uses a set of filtering rules—some visible, some buried—that decide whether a comment goes live, waits for approval, or gets junked.

    Understanding how these filters work lets you tune moderation to match your traffic pattern. If you run a low-volume blog, you can loosen the gate. If you attract drive-by spam, you tighten it. The defaults are conservative, built for a web that doesn’t exist anymore.

    The approval workflow: three possible destinations

    Every comment WordPress receives lands in one of three places: approved and published immediately, held in the moderation queue, or sent to spam (or trash, if you use an external filter like Akismet). The path depends on a chain of checks that run in sequence.

    First, WordPress checks whether the commenter has a previously approved comment using the same email address. If yes, and if the “Comment author must have a previously approved comment” box is checked under Settings → Discussion, the new comment publishes immediately. This is the fast lane for repeat commenters. If the box is unchecked, every comment waits for manual approval regardless of history.

    Next, WordPress scans the comment body, author name, email, URL, and IP address against two lists: the moderation keyword list and the disallowed keyword list. The moderation list (labelled “Comment Moderation” in the dashboard) holds comments for review. The disallowed list (formerly called the blacklist, relabelled in WordPress 5.5) sends comments straight to spam. Both lists live under Settings → Discussion and accept one keyword or phrase per line.

    Finally, WordPress counts links. By default, if a comment contains two or more links, it goes to moderation. You can change that threshold in the “Hold a comment in the queue if it contains [X] or more links” field. Set it to zero and every comment with any link gets held. Set it to ten and you let through link-heavy replies that are probably spam.

    Keyword matching: case-insensitive and substring-aware

    The keyword filters are simple but powerful. WordPress treats every entry as case-insensitive and matches substrings. If you add “casino” to the disallowed list, it will catch “casino,” “Casino,” and “online-casino-bonuses.” It will also catch “occasion” and “Casiano”—any string containing those letters in sequence.

    This substring behaviour causes false positives. A moderation list that includes “free” will flag “freedom,” “freelance,” and “gluten-free.” You can work around this by adding spaces before and after the keyword (” free “), which narrows the match to whole words surrounded by whitespace. It’s not perfect—it won’t catch “free!” or “free.”—but it reduces collateral damage.

    The moderation and disallowed lists work independently. A comment caught by the disallowed list never reaches the moderation queue; it skips straight to spam. A comment caught by the moderation list waits for manual review, even if the author has prior approved comments.

    IP and email history: where external plugins step in

    WordPress core doesn’t maintain a reputation database for IP addresses or email domains beyond the simple “previously approved” check. It doesn’t track how many times an IP has been flagged, or whether an email domain is a known spam source. For that, you need a plugin.

    Akismet, bundled with most WordPress installs, sends every comment to its cloud service for scoring. It checks the comment content, author metadata, and submission context against a global spam database and returns a spam/not-spam verdict. Akismet’s accuracy is high, but it’s a third-party dependency with a commercial pricing tier (checked October 2026) for business sites. Free usage is limited to personal blogs.

    Antispam Bee, a privacy-focused alternative, runs locally and uses pattern matching, honeypot fields, and country-based IP filtering. It doesn’t phone home, but it also doesn’t benefit from network-effect spam detection. Which tool fits depends on your privacy stance and comment volume.

    When to adjust the defaults

    If you’re launching a new site with zero comment history, uncheck “Comment author must have a previously approved comment.” Otherwise, every first-time commenter—including engaged readers—waits in the queue, and you create friction where you want conversation.

    If your niche attracts keyword-heavy spam (crypto, pharma, affiliate), populate the disallowed list early. Start with obvious terms and expand as patterns emerge. But review the spam folder weekly; automated filters drift and catch legitimate comments over time.

    If you cross-post to social media and drive external traffic, raise the link threshold to three or four. Readers who quote sources or share related articles shouldn’t wait for approval. If spam is minimal, you can disable link-count moderation entirely by leaving the field blank or setting it to a high number.

    The comment system in WordPress hasn’t changed much in a decade, but the web around it has. Spam is more sophisticated, and legitimate commenters expect instant feedback. Tuning the moderation filters to match your traffic pattern is a small lever that improves the reader experience without adding workload.

    Want more infrastructure walkthroughs like this? Subscribe to One Two Three Send—we break down the mechanics of online-business tools every week, no fluff.

  • Newsletter archive search: why most platforms bury your best content

    Newsletter archive search: why most platforms bury your best content

    Newsletter archive search: why most platforms bury your best content
    Photo: Unknown via Wikimedia Commons (Public domain)

    You’ve published 200 issues. Subscribers know you wrote something about API rate limits last spring, but they can’t find it. They scroll your archive page, give up, and email you instead—or worse, they unsubscribe because they think you never covered it.

    Archive search should be table stakes for any newsletter platform in 2026. It isn’t. Most platforms either hide it, break it with paywall logic, or never built it at all. The result: your back catalog—often your most valuable evergreen content—becomes invisible the moment it leaves the inbox.

    What archive search actually does (and doesn’t)

    Archive search lets readers query your published posts by keyword, usually from a public-facing page. It’s not the same as your platform’s internal post search (the one you use in the editor to find drafts). Reader-facing search needs to index published content, respect paywall settings, and return results fast enough that people don’t bounce.

    Good archive search indexes headlines, body text, and sometimes metadata like tags or categories. Bad implementations only search titles, or they index paywalled content but show locked snippets that frustrate readers. The worst case: no search at all, just a paginated list sorted by publish date.

    How the major platforms handle it

    Substack offers archive search on every publication’s homepage and archive page. It’s fast, indexes full text, and respects paywall boundaries—free subscribers see free posts, paid subscribers see everything. The search bar sits at the top of the archive by default. (Substack support docs, checked October 2026.)

    Beehiiv added archive search in late 2025. It’s available on the public archive page for all tiers, indexes post titles and body content, and filters by free vs. premium. The implementation is slower than Substack’s—queries can take two or three seconds on archives over 500 posts—but it works. (Beehiiv features page, checked October 2026.)

    ConvertKit does not offer built-in archive search. The public archive page lists posts chronologically with no search box. If you want search, you need to embed a third-party tool like Algolia or build a custom solution using ConvertKit’s API and a static site generator. Most operators don’t bother. (ConvertKit help center, checked October 2026.)

    Ghost includes archive search by default on its public site. Because Ghost runs as a full website CMS, search works across posts, pages, and tags. It’s one of the platform’s strongest discoverability features, especially for operators who treat their newsletter as a content library. (Ghost help docs, checked October 2026.)

    MailerLite does not provide archive search. The platform’s blog/landing-page builder lets you display recent posts, but there’s no search index for readers. If you’re using MailerLite and want searchable archives, you’ll need to host them elsewhere—usually WordPress or a static site. (MailerLite features, checked October 2026.)

    Why this matters more than open rates

    Open rates measure what happens in the first 48 hours. Archive search measures what happens in month six, month twelve, and year two. Evergreen content—tutorials, tool comparisons, case studies—drives long-tail signups and reduces support load. If readers can’t find it, you’re recreating the same content every quarter.

    Operators who migrate from platforms without search to platforms with it report two consistent changes: referral traffic from archive pages increases, and “hey, did you ever write about…” emails drop. Both compound over time. A searchable archive turns your newsletter into a reference library instead of a chronological feed that only rewards the most recent readers.

    What to do if your platform doesn’t have it

    If you’re on ConvertKit or MailerLite and archive search matters to your business, you have three options. First, migrate to a platform that supports it—Ghost and Substack are the strongest here. Second, build a custom archive using your platform’s API, a static site generator like Hugo or Eleventy, and a search tool like Pagefind or Algolia. Third, accept the limitation and organize your archive by category or tag, then link prominently to high-value posts in your welcome sequence and website nav.

    The third option is the lowest-friction compromise, but it only works if you have fewer than 50 posts or a tightly focused editorial niche. Once you cross 100 issues, manual curation doesn’t scale.

    Want more breakdowns like this? Subscribe to One Two Three Send for weekly deep-dives on the tools and tactics that power content-driven online businesses. Reply with the feature you want dissected next.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • Productivity tool trial periods: what resets when you re-signup

    Productivity tool trial periods: what resets when you re-signup

    Productivity tool trial periods: what resets when you re-signup
    Photo by Jakub Żerdzicki on Unsplash

    You canceled Notion three months ago. Now you want to try it again. Will your old workspace still be there? What about your Zapier connections, your API keys, your team invitations?

    Most productivity tools advertise 14-day trials. Fewer tell you what happens when you cancel, wait, then sign up again under the same email. Some platforms treat you as a returning user. Others wipe everything and start fresh. The difference costs you hours of reconfiguration—or worse, lost work.

    Here’s what actually persists, what gets deleted, and how long you have before the window closes.

    Account data vs. workspace data

    When you cancel a SaaS subscription, two clocks start. One governs your account—your login, email, and billing history. The other governs your workspace—projects, documents, settings, and integrations.

    Your account almost never expires. Platforms like Airtable, Notion, and ClickUp keep your login active indefinitely, even if you haven’t paid in years. You can sign back in anytime.

    Your workspace expires on a schedule that varies wildly:

    • Notion: Keeps your workspace read-only for 30 days after cancellation. After that, it’s deleted. Re-signup within the window, and everything restores when you resubscribe.
    • Airtable: Free-tier bases stay live indefinitely. Paid-tier features (like sync, longer revision history) disappear immediately, but your data remains.
    • ClickUp: Downgrades you to the free plan. No deletion. You lose advanced views and automations, but tasks and docs persist.
    • Coda: Locks docs to read-only after 21 days of non-payment. Deletes them after 90 days.

    If you’re trialing a tool you might return to later, check the help docs for “data retention after cancellation.” Most bury this in billing FAQs, not the trial signup flow.

    Integrations don’t wait for you

    Zapier, Make, and API-connected tools treat canceled accounts as dead endpoints. When your productivity app subscription lapses, two things break:

    OAuth tokens expire. If you connected your tool via “Log in with [App],” that token usually expires 30–90 days after your subscription ends. Zapier won’t throw an error immediately—it’ll keep trying to send data, fail silently, then pause the Zap after a few days of repeated failures.

    Webhooks stop firing. If you built automations that trigger when a task is created or a doc is updated, those webhooks die the moment your workspace goes read-only. Re-subscribing doesn’t resurrect them. You have to reconnect manually.

    The cleanest workaround: don’t cancel mid-automation. If you’re testing a tool that’s wired into your workflow, finish the trial, export your setup (most tools offer JSON exports of automation configs), then cancel. When you return, you can reimport instead of rebuilding.

    Team invitations and permissions reset

    If you invited collaborators during your trial, their access usually survives downgrades—but their role doesn’t.

    Notion downgrades all paid-tier teammates to guests. They can still comment, but they can’t edit or create new pages. When you resubscribe, you have to manually re-elevate them.

    Airtable keeps collaborators at their original permission level if you stay on the free tier. But if you trialed Enterprise, then downgraded, then upgraded to Pro six months later, field-level permissions and advanced sharing settings don’t restore. You start from scratch.

    ClickUp is the exception: it keeps team roles intact even on the free plan. You just lose features like custom roles and granular permissions.

    If you’re trialing tools for a team, screenshot your permission settings before you cancel. Most platforms don’t version-control this.

    The second-trial loophole

    Some platforms let you trial again. Others don’t.

    Notion, Airtable, and Coda allow one trial per email address, ever. If you cancel and want to test new features six months later, you need a new email—or you pay immediately.

    ClickUp and Monday.com are more permissive. They’ll offer you another 14-day trial if you’ve been gone for 90+ days. The trial counter resets, but your old workspace data doesn’t reload unless you kept it on the free tier.

    Zapier offers unlimited 14-day trials of premium plans if you’re already on the free tier. You can test different tiers (Professional, Team, Company) separately. Each trial starts fresh, but your free-tier Zaps keep running in the background.

    The cleanest move: if you know you’ll want to trial again in a few months, keep a free-tier account active. Don’t cancel entirely. Downgrade instead. You’ll skip the re-onboarding flow and keep your workspace intact.

    What to export before you cancel

    Even if you plan to return, export three things:

    • Raw data. CSV, JSON, or Markdown exports of your docs, tasks, or tables. Most tools bury this under Settings → Export or Admin → Backup.
    • Integration configs. Screenshot your Zapier triggers, API keys, and webhook URLs. These don’t transfer when you reconnect.
    • Workspace settings. Custom fields, templates, and permission schemes rarely survive the downgrade-upgrade cycle cleanly.

    If you’re trialing a tool seriously, treat the last day of the trial like a production cutover. Don’t just let it lapse.

    Got a question about a specific tool’s retention policy? Reply to this email—we’ll dig into it and share what we find in a future issue. Subscribe here if you want the answer delivered when it’s ready.

  • AI assistants repeat themselves when you don’t set temperature

    AI assistants repeat themselves when you don’t set temperature

    AI assistants repeat themselves when you don't set temperature
    Photo: Emeka Udenze via Wikimedia Commons (CC0)

    If you’ve ever run the same prompt twice and gotten word-for-word identical responses, or watched an AI assistant spiral into repetitive loops, you’ve seen temperature at work—or not working.

    Temperature is a parameter that controls how much randomness an AI model injects into its output. It’s not hidden deep in developer docs; most consumer AI tools expose it. But most solo operators never touch it, which means they’re stuck with whatever default the platform chose.

    Here’s how it works, when to adjust it, and one non-obvious way it breaks your workflow if you leave it on autopilot.

    What temperature actually controls

    When an AI model generates text, it doesn’t pick the single “best” next word. It assigns probabilities to thousands of candidates, then samples from that distribution.

    Temperature adjusts the shape of that distribution:

    • Temperature 0 (or close to it): the model always picks the highest-probability token. Output is deterministic. Run the same prompt ten times, you get ten identical responses.
    • Temperature 0.7–1.0: the model samples more widely. You get variety, creativity, and occasional surprises—some useful, some not.
    • Temperature above 1.5: the distribution flattens. Low-probability words get picked more often. Output becomes incoherent or tangential fast.

    Most platforms default to 0.7 or 1.0. Claude defaults to 1.0. OpenAI’s ChatGPT sits around 0.7 in the web interface. Google’s Gemini models vary by endpoint.

    That default is optimized for general chat. It’s not optimized for your use case.

    When to drop temperature to zero

    If you’re using AI to generate structured output—JSON schemas, CSV rows, code snippets, form letters, product descriptions from a template—you want deterministic results.

    Set temperature to 0. You’ll get the same output every time, which makes testing, debugging, and batch processing predictable. If the first result is wrong, the prompt is wrong. Fix the prompt, not the dice roll.

    Example: you’re generating meta descriptions for 200 blog posts. You write a prompt, test it on three posts, and it works. You run the batch overnight at temperature 0.7. In the morning, 180 are perfect and 20 are off-brand or too long. You can’t tell which prompt variation caused the problem, because the model sampled differently each time.

    Drop to temperature 0. Now every meta description follows the same logic. If one breaks, they all break the same way—and you can fix the root cause in one edit.

    When to raise temperature above default

    Brainstorming, headline variants, subject-line testing, social-post angles—anything where you want the model to surprise you benefits from higher temperature.

    Set it to 1.2 or 1.3. You’ll get weirder suggestions, some of which will be unusable. But the hit rate on novel ideas goes up. Run the same prompt five times and you’ll see real divergence, not just synonym swaps.

    One catch: higher temperature increases the chance of hallucination and off-topic drift. Don’t use it for factual research or anything that feeds directly into customer-facing copy without review.

    The non-obvious problem: mid-conversation drift

    Most AI chat interfaces don’t let you adjust temperature per message. The setting applies to the whole conversation thread.

    If you start a thread at temperature 1.0 to brainstorm blog topics, then shift gears and ask the model to write a structured outline, you’re still sampling at 1.0. The outline will vary every time you regenerate it, which makes it hard to iterate on structure without the content shifting under you.

    The fix: start a new conversation when you switch from exploratory mode to execution mode. Or use an API client or playground interface (OpenAI, Anthropic, and Google all offer them) where you can set temperature per request.

    For solo operators running prompt-based workflows—newsletter intros, product descriptions, SEO meta fields—this matters more than model size or context window. A smaller model at the right temperature will outperform a bigger one set to default.

    Check your tool’s settings. If you’re using Claude via the web interface, click the model dropdown and look for “temperature” or “sampling.” If you’re calling an API, it’s almost always exposed as a parameter. If you’re using a no-code AI tool like Zapier’s ChatGPT action or Make’s OpenAI module, temperature is in the advanced settings.

    Set it once per workflow type. You’ll spend less time regenerating and more time shipping.

    Want more breakdowns of the settings nobody explains? Subscribe to One Two Three Send—one operator-focused article every day, no fluff.

    Heads up — some links in this article are affiliate links. If you sign up through them, we may earn a small commission at no extra cost to you. We only recommend tools we use ourselves.

  • WordPress auto-save intervals: how often drafts write and when you lose work

    WordPress auto-save intervals: how often drafts write and when you lose work

    WordPress auto-save intervals: how often drafts write and when you lose work
    Photo by Markus Winkler on Unsplash

    WordPress auto-save is supposed to be invisible. You type, it saves, and you never think about it—until you refresh a draft and realise the last four paragraphs are gone.

    The default auto-save interval is 60 seconds. That’s a full minute of typing that can vanish if your browser crashes, your session times out, or a plugin interferes with the AJAX request that writes the draft to the database.

    Most solo operators don’t realise how often WordPress doesn’t save, or what conditions break the cycle. Here’s what actually happens, and how to adjust it if you’re losing work.

    How WordPress auto-save works

    WordPress fires an AJAX request to wp-admin/admin-ajax.php every 60 seconds while you’re editing a post or page. That request writes a revision to the wp_posts table with post_status = 'auto-draft'.

    If the request succeeds, you’ll see a faint “Draft saved at [time]” notice near the top of the editor. If it fails—because your session expired, your network dropped, or a security plugin blocked the request—you’ll see nothing. WordPress assumes the save worked.

    The problem: WordPress doesn’t retry failed auto-saves. If the AJAX call times out or returns a 403, the next save attempt happens 60 seconds later. Anything you typed in between is at risk.

    This is especially common on shared hosting, where PHP execution time limits, memory caps, or aggressive WAF rules can silently kill the auto-save request. You’ll only notice when you reload the page or lose focus and see an older version of your draft.

    When auto-save fails silently

    Four scenarios break auto-save more often than operators expect:

    • Multiple tabs editing the same post. WordPress locks posts to a single session, but if you open the same draft in two browser tabs, the second tab’s auto-save requests return 409 conflicts. The editor doesn’t warn you—it just stops saving.
    • Session timeout during long edits. Default WordPress sessions expire after 48 hours, but hosting providers often override this to 2–12 hours. If your auth cookie expires mid-edit, auto-save returns 401 and stops. You’ll only notice when you hit Publish and get bounced to the login screen.
    • Security plugins blocking AJAX. Wordfence, Sucuri, and iThemes Security all have rules that can block rapid-fire AJAX requests from the same IP. If you’re editing quickly, the plugin may flag auto-save as suspicious and return 403. Check your security log—most operators never look.
    • Browser background-tab throttling. Chrome, Safari, and Edge all throttle JavaScript timers in background tabs to save battery. If you’re editing a post in one tab while reading documentation in another, the auto-save interval can stretch to 2–5 minutes instead of 60 seconds.

    How to shorten the auto-save interval

    WordPress lets you override the 60-second default with a single line in wp-config.php:

    define( 'AUTOSAVE_INTERVAL', 30 );

    That changes the interval to 30 seconds. You can set it as low as 10 seconds, but be aware: shorter intervals increase database writes and server load. If you’re on shared hosting with tight I/O limits, aggressive auto-save can slow down the editor or trigger rate-limit warnings from your host.

    A better approach for most solo operators: leave the interval at 60 seconds, but add client-side protection with a browser extension like Textarea Cache (Chrome) or Lazarus (Firefox). These tools store form content in local browser storage every few seconds, independent of WordPress. If the page crashes or the session expires, you can recover the text from the extension’s cache.

    What gets saved and what doesn’t

    WordPress auto-save only writes the post title, content, and excerpt. It does not save:

    • Custom field values (ACF, Pods, or manual meta fields)
    • Featured image selections
    • Category or tag assignments
    • Gutenberg block settings (only the block HTML is saved, not inspector-panel metadata)

    If you’re using a page builder like Elementor or Bricks, auto-save behaviour is entirely different—they maintain their own revision systems and save intervals. Check the plugin’s settings; most default to 60–120 seconds and store data in custom database tables, not wp_posts.

    When to disable auto-save

    Some operators disable auto-save entirely to reduce database bloat, especially on sites with hundreds of posts and thousands of revisions. You can turn it off with:

    define( 'AUTOSAVE_INTERVAL', 86400 );

    That sets the interval to 24 hours—effectively disabling it. But unless you’re manually saving every few minutes with Cmd+S or Ctrl+S, this is risky. A single browser crash can lose an hour of work.

    A safer middle ground: leave auto-save enabled, but limit the number of revisions WordPress stores. Add this to wp-config.php:

    define( 'WP_POST_REVISIONS', 5 );

    That keeps only the five most recent revisions per post. It prevents database bloat without removing the safety net.

    Reply and let us know: Have you ever lost a draft to a failed auto-save? What interval do you run, and have you adjusted it? Hit reply—we read every response.