Author: onetwothreeadmin

  • Transactional email deliverability: why marketing ESPs tank it

    Transactional email deliverability: why marketing ESPs tank it

    Transactional email deliverability: why marketing ESPs tank it
    Photo by Miguel Ángel Padriñán Alba on Unsplash

    Most solo operators send two types of email through the same platform: newsletters and transactional messages. That’s a mistake that shows up in your inbox placement rate—and you won’t see it until a customer complains they never got their password reset.

    Transactional email—password resets, order confirmations, login codes, payment receipts—requires different infrastructure than marketing email. The delivery expectations are stricter, the failure modes are different, and the IP reputation dynamics don’t overlap.

    Here’s what changes when you split them, and when it’s worth the overhead.

    Marketing and transactional email use different reputation signals

    When you send a newsletter, mailbox providers evaluate your sender reputation over days or weeks. A few spam complaints or low engagement rates get averaged into a rolling score. You can recover from a bad send.

    Transactional email doesn’t get that grace period. A password reset that doesn’t arrive in thirty seconds is a failed transaction. Mailbox providers know this. They evaluate transactional senders on speed, consistency, and complaint rate—but complaints on transactional mail are rare, because recipients explicitly requested the message.

    When you send both through the same IP pool, your newsletter engagement rate drags down your transactional delivery. A single newsletter with weak engagement can delay order confirmations for hours while your shared IP gets throttled by Gmail.

    Postmark, which specializes in transactional delivery, maintains separate IP pools and enforces a strict no-marketing policy for exactly this reason. Their average transactional delivery time is under two seconds because they never let marketing volume pollute the reputation of those IPs.

    Volume spikes break transactional delivery when mixed with marketing

    Newsletter platforms are built to handle scheduled batch sends. You queue 10,000 emails at 9 a.m. and they go out over twenty minutes. That’s expected behavior.

    Transactional email is bursty and unpredictable. A product launch might trigger 500 order confirmations in three minutes. A password breach forces 2,000 reset emails in an hour. The platform needs to send immediately, not queue behind your weekly newsletter.

    When you mix both on a single ESP, you create a priority conflict. Beehiiv and MailerLite both handle transactional sends, but they’re optimized for scheduled marketing volume. If your newsletter is mid-send and a customer checks out, that order confirmation might wait in line.

    Dedicated transactional platforms route urgent messages through priority queues. Postmark guarantees delivery attempts within ten seconds. Brevo offers separate IP pools for transactional vs. marketing, but you need to configure them—it’s not the default.

    Compliance and logging requirements differ

    Marketing email in 2026 requires an unsubscribe link in every message, a physical mailing address, and compliance with CAN-SPAM or GDPR consent rules depending on your audience location.

    Transactional email is exempt from most of those rules—because it’s fulfilling a user-initiated action. You don’t need an unsubscribe link in a password reset. You don’t need consent to send an invoice.

    But mixing them on the same platform means your transactional templates might inherit marketing-compliance features you don’t need. Worse, some platforms apply the same suppression list to both. If a user unsubscribes from your newsletter, they might also stop receiving order confirmations.

    Separate platforms let you enforce different retention and logging policies. Transactional sends often need longer log retention for audit or dispute resolution—Postmark keeps logs for 45 days, longer than most marketing ESPs.

    When to split, and what it costs

    If you’re sending fewer than 100 transactional emails per month, the overhead of a second platform isn’t worth it. Stay on your marketing ESP and monitor delivery.

    Split when:

    • You send more than 500 transactional emails per month
    • Customers report missing password resets or payment confirmations
    • You run a product with user signups, checkouts, or account actions that require immediate email
    • Your newsletter volume fluctuates and you need guaranteed transactional speed

    Postmark charges $15/month for 10,000 transactional emails, with delivery logs and dedicated IPs included. Brevo offers 300 free transactional emails per day on their free tier, then $25/month for higher volume with separate IP pools.

    You’ll integrate via SMTP or API. Most platforms—WordPress, Shopify, custom apps—support both. SMTP is easier for legacy systems; API gives you more granular delivery webhooks and retry control.

    Migration takes two hours, not two days

    Moving transactional email off your marketing ESP is simpler than migrating your newsletter list. You’re changing a configuration setting, not exporting CSVs.

    In WordPress, install the Postmark or Brevo plugin, authenticate with your API key, and route wp_mail() calls through the new service. In a custom app, swap your SMTP credentials or API endpoint. Test with a password reset and a sample order confirmation.

    The hardest part is updating DNS records—you’ll need to add new SPF and DKIM entries without breaking your existing marketing setup. Most transactional platforms provide a DNS validation tool that checks your records before you go live.

    Once it’s running, monitor your delivery rate in the transactional platform’s dashboard. If you’re seeing 99%+ delivery within ten seconds, you’ve fixed the problem your marketing ESP was quietly causing.

    Want more infrastructure breakdowns like this? Subscribe to One Two Three Send and get operator-focused tool explainers every week—no fluff, just the technical details that affect your delivery and revenue.

    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.

  • AI token counting is broken—and it’s costing you per request

    AI token counting is broken—and it’s costing you per request

    AI token counting is broken—and it's costing you per request
    Photo by Roman Manshin on Unsplash

    If you’re running AI workflows at scale—content generation, summarization, classification—you’ve probably noticed your API bills don’t match your mental math. You estimate 5,000 tokens per request, the platform charges you for 7,200, and there’s no line item explaining the gap.

    The problem isn’t hidden fees. It’s that token counting isn’t standardized, and most platforms count more than the text you send.

    What platforms actually count as tokens

    When you send a prompt to an AI model, you’re not just billed for the words in your input and output. You’re also charged for:

    • System instructions — the hidden prompt that sets behavior (e.g., “You are a helpful assistant”). On some platforms, this adds 50–150 tokens per request, whether you write it or use the default.
    • Formatting tokens — JSON structure, markdown syntax, and special delimiters all count. A 200-word response formatted as JSON can cost 20–30% more than plain text.
    • Function call schemas — if you’re using tools or structured outputs, the schema definition gets tokenized and billed every single request, even if the model doesn’t invoke the function.
    • Conversation history — in multi-turn chats, the entire thread gets re-sent with each new message. A 10-turn conversation means your 11th message is billed for all prior context.

    Claude, GPT-4, and Gemini all tokenize differently. The same 500-word prompt can vary by 15% across platforms because of how they handle whitespace, punctuation, and non-English characters.

    How to audit what you’re actually being billed for

    Most API dashboards show total tokens per request, but they don’t break out input vs. output vs. overhead. Here’s how to measure it yourself:

    Use the platform’s tokenizer tool. OpenAI offers a public tokenizer at platform.openai.com/tokenizer. Anthropic has a similar tool in their API docs. Paste your exact prompt—including system instructions and any JSON formatting—and compare the count to what your API response reports.

    Log the token counts returned in API responses. Most platforms return usage.prompt_tokens and usage.completion_tokens in the response object. Store these alongside your request text in a database or CSV. After a week, calculate the average overhead: total billed tokens minus your estimated input/output length.

    Test with and without function schemas. If you’re using structured outputs or tool calling, run the same prompt twice—once with the schema, once without. The delta is what the schema costs you per request. If it’s 200+ tokens and you’re making 10,000 requests a month, that’s $4–$12 in silent overhead (depending on the model).

    The non-obvious fix: prompt caching

    Some platforms now offer prompt caching, which stores repeated sections of your input and bills them at a fraction of the normal rate. Anthropic introduced this in mid-2026; OpenAI has a similar feature for GPT-4 Turbo.

    If you’re sending the same system instructions, reference documents, or function schemas with every request, caching can cut your effective input cost by 50–90%. But it only works if the repeated section is identical across requests—down to the character. A single whitespace difference breaks the cache.

    Here’s the trick: template your prompts so the static parts come first, and the variable parts (user input, dynamic data) come last. Cache the prefix. For example:

    • Cached prefix: system instructions + JSON schema + reference examples (1,500 tokens)
    • Variable suffix: user-provided text (200–500 tokens)

    On a cached request, you’re only billed full-rate for the 200–500 variable tokens. The 1,500-token prefix costs ~10% of normal. Over 10,000 requests, that’s the difference between $150 and $18.

    When token bloat doesn’t matter—and when it does

    If you’re running a few dozen requests a day for summarization or drafting, the overhead is noise. You’ll spend more time auditing than you’ll save.

    But if you’re processing user-generated content at scale—classifying support tickets, generating product descriptions, scoring leads—token bloat compounds fast. A 20% miscalculation on 50,000 requests per month is $200–$400, depending on the model.

    The fix isn’t switching platforms. It’s measuring what you’re actually being charged for, trimming the fat (verbose system instructions, redundant examples), and caching anything that repeats.

    Want more breakdowns like this? Subscribe to One Two Three Send—we explain one under-documented tool behavior every week, with the numbers platforms don’t advertise.

    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 API rate limits: what happens when you hit the wall

    Social media API rate limits: what happens when you hit the wall

    Social media API rate limits: what happens when you hit the wall
    Photo by Jay Openiano on Unsplash

    If you publish to multiple social platforms through a scheduler or automation tool, you’ve already used an API—whether you know it or not. Every time your tool posts on your behalf, it makes a call to that platform’s application programming interface. And every platform caps how many calls you can make in a given window.

    Hit that cap, and things stop working. Not always with a clear error message. Sometimes your posts just don’t go out. Sometimes they queue silently. Sometimes your entire account gets temporarily locked.

    Here’s what actually happens when you hit rate limits, how platforms differ, and what your scheduling tool does—or doesn’t do—to protect you.

    How platforms meter API calls

    Rate limits aren’t uniform. Twitter’s API (now X) uses a 15-minute rolling window for most endpoints. Instagram’s Graph API counts requests per hour and per day. LinkedIn measures calls per application and per user token. Facebook uses a complex credit system that resets hourly but penalizes burst traffic.

    Most solo operators don’t interact with these APIs directly—they use tools like Publer, Buffer, or Hootsuite. But those tools share API quota across all their users. When you schedule a post, your tool makes the call on your behalf using either a shared app token or an individual user token tied to your OAuth login.

    Shared tokens mean one power user can exhaust the quota for everyone. Individual tokens mean your usage is isolated, but you’re responsible for staying under the threshold—and most tools don’t surface how close you are.

    What breaks when you hit the limit

    The immediate symptom: your scheduled post doesn’t publish. What happens next depends on the platform and the tool.

    Twitter rate limits return a 429 Too Many Requests response. Most schedulers retry automatically after the window resets. But if you’ve queued 50 posts to go out in a 15-minute span, only the first batch publishes. The rest either fail silently or get pushed to the next available slot—sometimes hours later, sometimes never.

    Instagram’s API doesn’t just reject the call. Repeated limit violations can trigger a temporary block on your account, not just the tool. That block can last 24 hours. During that window, even manual posts from the Instagram app may be throttled or flagged as spam.

    LinkedIn’s API returns a Retry-After header telling your tool how long to wait. Well-designed schedulers respect that. Poorly designed ones hammer the endpoint every few seconds, which extends the lockout and can flag your app token as abusive.

    Facebook’s credit system is the most opaque. You don’t get a hard cutoff—you get throttled. Posts slow down. Media uploads time out. The tool may report success while the post sits in limbo for 20 minutes before finally appearing.

    How schedulers handle rate limits (or don’t)

    Not all tools handle this gracefully. Some retry intelligently. Some fail and log the error. Some do nothing and leave you wondering why yesterday’s post never went live.

    Publer, for instance, uses individual OAuth tokens and queues retries when it hits a rate limit. If a post fails due to API throttling, it shows a warning in your dashboard and attempts redelivery during the next window. You can manually re-queue if needed.

    Buffer retries up to three times, spaced 60 seconds apart. After that, the post is marked as failed, and you get an email. No automatic rescheduling—you have to manually repost or edit the queue.

    Hootsuite logs the failure but doesn’t always surface it prominently. If you don’t check the message center, you might not know a post didn’t go out until a follower asks why you went silent.

    Zapier and Make (formerly Integrabuild) treat social posts as individual automation tasks. If an API call fails, the entire automation fails. Depending on your plan, it may retry once or stop completely. There’s no built-in queue—just a failed task log you have to monitor.

    How to avoid hitting the wall

    First, batch your posts sensibly. Don’t schedule 20 LinkedIn updates to publish in the same hour. Spread them across the day. Most platforms are fine with one post every 15–30 minutes; anything tighter risks hitting burst limits even if your daily quota is fine.

    Second, know your tool’s architecture. Does it use shared or individual tokens? If shared, you’re at the mercy of other users’ activity. If individual, you control your own quota—but you’re also solely responsible for staying under it.

    Third, monitor your dashboard. Most schedulers show failed posts, but not all surface why they failed. Look for terms like “rate limit,” “throttled,” or “429 error.” If you see repeated failures at the same time of day, you’re likely hitting a window boundary.

    Fourth, use native scheduling when possible for high-volume accounts. Facebook’s Creator Studio, LinkedIn’s native scheduler, and Twitter’s own scheduling UI don’t count against third-party API limits. If you’re publishing more than 10 times a day to a single platform, native tools are often more reliable—and free.

    When rate limits actually help

    Rate limits aren’t purely punitive. They prevent spam, protect platform performance, and force you to think about whether you’re over-posting. If you’re routinely hitting API caps, the bottleneck isn’t the platform—it’s your publishing cadence.

    One operator I spoke with was scheduling 15 Twitter threads a day through Zapier, triggered by new blog posts in an RSS feed. Half the threads never posted. The issue wasn’t Zapier—it was that 15 threads in 24 hours, each requiring multiple API calls to thread replies together, exceeded Twitter’s per-user limit. Switching to three threads a day, manually curated, worked better and got more engagement.

    Rate limits force editorial discipline. If you can’t automate your way to volume, you have to prioritize quality.

    One Two Three Send is written for operators who want their tools to work predictably. If you run into a rate-limit mystery—or solve one—reply and let us know. We’ll cover it.

    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.

  • Facebook Ads Library search: how to reverse-engineer a competitor’s funnel

    Facebook Ads Library search: how to reverse-engineer a competitor’s funnel

    Facebook Ads Library search: how to reverse-engineer a competitor's funnel
    Photo by Erik Mclean on Unsplash

    Facebook’s Ad Library is a public archive of every active ad running across Meta platforms. It was built for transparency, but it’s become one of the most underused research tools for solo operators building traffic and product funnels.

    Most people know it exists. Almost no one uses it systematically. Here’s how to extract real competitive intelligence from it without spending hours clicking through thousands of impressions.

    What the Ad Library actually shows you

    The tool lives at facebook.com/ads/library. You can filter by advertiser name, keyword, region, and platform (Facebook, Instagram, Messenger, Audience Network). Once you search, you see every active ad from that advertiser—creative, copy, CTA button, and live start date.

    What it doesn’t show: spend, impressions, click-through rates, or targeting criteria. You’re working with the front end of the funnel only. But that’s enough to reverse-engineer positioning, offer structure, and creative patterns.

    For operators running paid acquisition or testing new products, this is free market research that updates in real time.

    How to build a competitor snapshot in under 20 minutes

    Pick three competitors in your niche. Search each by business name. Open every active ad in a new tab. Now ask:

    • What’s the primary hook in the headline? Problem-focused, benefit-focused, or curiosity-driven?
    • What’s the destination—landing page, lead magnet, product page, or newsletter signup?
    • What format dominates—single image, carousel, video, or text-only?
    • How long has each ad been running? If something’s been live for 60+ days, it’s probably working.

    Screenshot the ads. Drop them into a shared doc or Notion database with those four data points. Do this once a month. You’ll spot pattern shifts before your competitors do.

    One operator I know runs this audit every two weeks for five SaaS brands in her vertical. She noticed three of them switched from lead-magnet funnels to free-trial CTAs within a 10-day window in July. She tested the same shift and cut her cost-per-signup by 40%.

    Where the data gets noisy—and how to filter it

    Not every ad in the Library is current strategy. Brands run tests, pause campaigns, and leave remnants live for weeks. If you see 40 ads from one advertiser, most are noise.

    Focus on:

    • Ads with a start date in the last 30 days
    • Ads running across multiple placements (Facebook + Instagram usually signals confidence)
    • Ads with multiple versions of the same hook or offer (indicates active iteration)

    Ignore single-variant ads older than 60 days unless the brand is known for evergreen campaigns. They’re often forgotten tests or compliance placeholders.

    Also: the Library indexes ads by the page name, not the parent company. If a brand runs multiple Facebook pages, you’ll need to search each separately. Check the “Page transparency” section on their main page to find alternate entities.

    Two non-obvious uses for solo operators

    First: use it to validate your own creative before you spend. If no one in your space is running video ads, there’s probably a reason—either the audience doesn’t convert on video, or production cost doesn’t pencil. If everyone’s running carousels with testimonial screenshots, test a variation on that format first.

    Second: track launch cycles. When a competitor floods the Library with 15 new ads in 48 hours, they’re either launching something or scaling a winner. Set a calendar reminder to check their site, email list, and social a week later. You’ll often find the full funnel.

    One more: if you’re pitching sponsorships or affiliates, the Ad Library shows you which brands are actively spending in your niche. That’s a better prospecting list than scraping Instagram or guessing from podcasts.

    The Library isn’t analytics. It won’t tell you what works. But it will show you what your market is betting on right now—and that’s worth more than most dashboard metrics when you’re deciding what to build next.

    Want breakdowns like this in your inbox? Subscribe to One Two Three Send for tool explainers, competitive tactics, and operator-tested workflows every week.

  • Zapier task history caps at 30 days—where your automation logs go

    If you’re running a content business on Zapier, you’ve probably built automations that move data between your newsletter platform, payment processor, CRM, and social scheduler. Most of those Zaps run quietly in the background—until something breaks.

    That’s when you open the task history panel, scroll back to find the failed run, and realize: Zapier only keeps logs for 30 days. If the error happened five weeks ago, the evidence is gone.

    This isn’t a bug. It’s a design decision that affects how you debug, audit, and prove compliance. Here’s what you need to know.

    What Zapier task history actually stores

    Every time a Zap runs, Zapier logs a task. That task record includes:

    • The trigger event (e.g., new subscriber in MailerLite, new payment in Stripe)
    • Each action step (e.g., add row to Google Sheets, send Slack message)
    • Input and output data for every step
    • Error messages, retry attempts, and timestamps

    On the Free plan, you get 7 days of history. On Starter, Professional, and Team plans, you get 30 days. Enterprise plans can negotiate longer retention, but most solo operators and small teams are on the 30-day tier.

    After 30 days, the task record disappears. You can’t export it. You can’t extend retention retroactively. It’s just gone.

    When 30 days isn’t enough

    Here are three scenarios where the retention cap becomes a real problem:

    Delayed payment disputes. A customer disputes a charge 45 days after purchase. You need to prove the automation fired correctly: that the access email was sent, the membership tag was applied, and the welcome sequence triggered. If your Zap ran seven weeks ago, you have no log.

    Quarterly reconciliation. You’re closing Q2 financials and notice a discrepancy between Stripe revenue and your CRM’s subscription count. You want to audit every payment-to-CRM sync event from April. But it’s July, and April’s logs are gone.

    Debugging legacy workflows. A subscriber reports they never received a lead magnet you sent in May. You want to check if the Zap fired when they confirmed their email. It’s now September. The task history shows nothing.

    In all three cases, you’re forced to reconstruct events from downstream systems—your ESP’s delivery logs, your CRM’s activity feed, your payment processor’s event history. That works sometimes. But it’s slower, incomplete, and you lose the step-by-step trace Zapier’s logs provide.

    What to log externally

    If you need a longer audit trail, you have to build it yourself. Here’s the simplest approach:

    Add a Google Sheets action to every critical Zap. After your main workflow completes, append a row to a private spreadsheet with the task ID, timestamp, trigger data, and key outputs. You now have a permanent record that lives outside Zapier’s retention window.

    This costs one extra task per run, but it’s worth it for high-stakes automations: payment confirmations, access grants, refund workflows, compliance events.

    Use a dedicated logging service. Tools like Logtail, Better Stack, or even a self-hosted Supabase table can accept webhook payloads. Add a webhook action at the end of your Zap and send a JSON payload with the data you need. This scales better than Sheets if you’re running thousands of tasks per month.

    Store error notifications differently. If a Zap fails, Zapier sends an email. Those emails live in your inbox forever—unless you archive them. Create a Gmail filter that labels Zapier error emails and keeps them out of trash. That way, even if the task log expires, you still have the failure notification and can trace it from there.

    One non-obvious tip

    Zapier’s API lets you fetch task history programmatically within the retention window. If you’re technical, you can write a weekly cron job that pulls the last seven days of tasks via the API and archives them to your own database. This is overkill for most operators, but if you’re subject to compliance requirements (GDPR data-processing logs, financial audits, SLA enforcement), it’s the only way to guarantee long-term retention.

    The Zapier API endpoint is https://api.zapier.com/v1/zaps/{zap_id}/tasks. You’ll need a paid plan and an API key. The response includes the same task data you see in the UI—trigger, actions, inputs, outputs, errors.

    Most operators won’t need this. But if you’re running a membership site, a paid community, or a SaaS product where access control is automated, it’s worth knowing the option exists.

    Want more breakdowns like this? Subscribe to One Two Three Send—we cover the infrastructure details other newsletters skip.

  • WordPress CDN integration: what rewrites URLs and what breaks

    WordPress CDN integration: what rewrites URLs and what breaks

    WordPress CDN integration: what rewrites URLs and what breaks
    Photo by Markus Winkler on Unsplash

    Content delivery networks promise faster load times by serving static assets—images, CSS, JavaScript—from geographically distributed servers. But CDN integration with WordPress isn’t plug-and-play. Different plugins rewrite URLs using different methods, and the approach you choose determines what works, what breaks, and how much control you keep.

    If you’ve ever turned on a CDN plugin only to find images missing, stylesheets unstyled, or dynamic features suddenly broken, you’ve hit the rewrite layer. Here’s what’s actually happening under the hood, and how to choose the right method for your setup.

    Three ways CDN plugins rewrite asset URLs

    Most CDN plugins—whether standalone tools or bundled with caching plugins—use one of three rewrite methods: output buffer replacement, content filter hooks, or database-level rewrites.

    Output buffer replacement captures the entire HTML document just before it’s sent to the browser, scans for URLs matching your site’s domain, and replaces them with your CDN URL. It’s simple and catches nearly everything, but it’s also the slowest method. Every page load requires a full-text search-and-replace operation on the HTML output. For sites serving thousands of requests per hour, that adds measurable overhead.

    Content filter hooks target specific WordPress functions—the_content, wp_get_attachment_url, style_loader_src—and rewrite URLs as they’re generated. This is faster than output buffering because it only touches URLs WordPress explicitly handles. But it misses anything outside those hooks: hardcoded image paths, custom shortcodes, third-party plugin assets that bypass WordPress’s media library.

    Database-level rewrites go further: they permanently change URLs stored in your database, replacing your domain with the CDN domain in post content, metadata, and widget settings. This is the fastest runtime option—no per-request rewriting—but it’s also the riskiest. If you later switch CDN providers or disable the CDN, you need to reverse the process. Miss a backup or a table, and you’re left with broken internal links.

    What breaks when dynamic content hits a static rewrite

    The most common failure mode: a CDN plugin rewrites URLs for content that shouldn’t be cached or served statically.

    If your site uses dynamic image generation—say, on-the-fly thumbnail resizing, watermarking, or user-uploaded avatars processed server-side—those URLs look like static assets to a CDN plugin. The rewrite happens, the CDN caches the first version it sees, and subsequent requests serve stale or incorrect images.

    The same issue hits API endpoints disguised as asset paths. Some plugins expose JSON feeds or AJAX handlers at URLs ending in .json or .js. A broad CDN rewrite rule treats those as cacheable static files, and your dynamic features stop responding to real-time data.

    The fix: CDN plugins that use output buffering or filter hooks typically let you exclude paths or file extensions. If you’re generating dynamic images under /uploads/dynamic/, exclude that path. If you’re serving live data via /api/feed.json, exclude .json endpoints or that specific path.

    Database rewrites don’t support exclusions—they’re all-or-nothing. That’s why most operators avoid them unless they’re working with purely static content and a staging environment where they can test reversals.

    When CDN URL rewriting conflicts with plugins

    Another edge case: third-party plugins that also rewrite URLs.

    Lazy-load plugins, for example, often replace image src attributes with placeholder data URIs and store the real URL in a data-src attribute. If your CDN plugin runs after the lazy-load plugin, it rewrites the placeholder but misses the data-src—so images never load.

    Security plugins that obfuscate admin-ajax.php paths or login URLs can collide with CDN rewrites that assume standard WordPress structure. The CDN tries to serve a cached version of a URL that no longer exists, and you get 404s on critical functionality.

    The solution is execution order. Most CDN plugins let you set their priority in the WordPress hook queue. If lazy-loading runs at priority 10, set your CDN rewrite to priority 15 so it processes the final HTML. If that’s not exposed in settings, you’re editing plugin code or switching tools.

    How to choose the right CDN rewrite method

    If your site is purely content-driven—blog posts, static images, CSS, JS—output buffer replacement works fine. The performance hit is negligible for most solo operators serving a few thousand monthly visitors, and you avoid the narrow scope of filter hooks or the permanence of database rewrites.

    If you’re running a membership site, ecommerce store, or any WordPress install with dynamic features, use filter-hook-based rewriting and configure exclusions carefully. Test user-facing features after enabling the CDN: login forms, checkout flows, comment submission, anything AJAX-driven.

    Avoid database rewrites unless you’re migrating a fully static archive or working with a developer who’s scripted both the rewrite and the rollback. The speed gain isn’t worth the risk for most operators.

    One more note: if you’re using a host with built-in CDN integration—BigScoots offers this, as do most managed WordPress hosts—the rewrite layer is handled server-side, outside WordPress. That’s the cleanest option because it doesn’t touch your database or add PHP overhead. You lose some fine-grained control, but you also eliminate an entire class of conflicts.

    Want more technical breakdowns like this? Subscribe to One Two Three Send for operator-focused how-tos, tool teardowns, and the infrastructure details that actually matter when you’re running your own site.

  • Stop trusting open rates—track reply rates instead

    Open rates have been broken since iOS 15 dropped Mail Privacy Protection in 2021. By 2026, most email platforms report inflated open metrics—often 20–40 percentage points higher than genuine engagement. Yet operators still use open rate as their primary health metric.

    Reply rate is the better signal. It’s harder to game, immune to privacy protection prefetch, and directly correlated with reader trust. If someone hits reply, they read your email. If your open rate is 68% but your reply rate is 0.02%, you have a surface-level audience, not an engaged one.

    Why open rates lie more now than ever

    Apple Mail Privacy Protection prefetches email content—including tracking pixels—whether the recipient opens the message or not. Gmail’s image proxy caching does something similar. Microsoft Outlook’s Focused Inbox prerenders previews. The result: platforms record an “open” even when the email was never seen by a human.

    For operators sending to audiences with high Apple Mail adoption (common in B2C wellness, design, and lifestyle niches), reported open rates routinely exceed 60%. That number doesn’t reflect intent. It reflects infrastructure.

    Click-through rate is more reliable than open rate, but it only captures a narrow behavior: the subset of readers who both engage and want to leave your email. Reply rate captures everyone who wants to continue the conversation inside the inbox.

    What reply rate actually measures

    Reply rate = (unique reply senders) / (delivered emails) over a given period. Most ESPs don’t surface this metric in dashboards. You’ll need to calculate it manually or use a dedicated tool.

    Postmark tracks replies natively if you configure inbound routing. Beehiiv doesn’t offer reply tracking in-platform as of mid-2026, but you can pipe replies into a shared inbox (Gmail, Front, Missive) and tag them by campaign. MailerLite requires a webhook setup to catch inbound mail.

    Typical reply rates for well-engaged lists:

    • 0.5–2% for broadcasting newsletters (one-to-many)
    • 3–8% for onboarding sequences or high-touch courses
    • 10–20% for tiny lists under 500 where the operator responds personally

    If you’re under 0.2%, your audience isn’t reading—or your writing doesn’t invite conversation.

    How to increase reply rate without begging

    Don’t end every email with “just hit reply!” That’s performative and readers ignore it. Instead, structure your content to naturally prompt response.

    Ask a single, specific question. Not rhetorical. Not broad. “What’s the biggest bottleneck in your content workflow right now?” beats “How’s your week going?”

    Share a half-formed opinion. Readers reply to refine, agree, or argue. “I think most operators over-index on SEO and under-invest in email” will get more replies than a polished thesis.

    Offer a binary choice. “I’m writing a guide on either WordPress caching or CDN setup next week—reply A or B.” Low friction, clear action, built-in reason to respond.

    Reply to every reply in the first 30 days. It trains your audience that replying works. After that, you can batch responses weekly or spotlight interesting replies in the next send.

    When reply rate doesn’t matter

    If you’re running a pure news digest, a curated link roundup, or a high-volume daily brief, reply rate isn’t your north star. Those formats succeed on speed and brevity, not conversation.

    Same if you’re monetizing exclusively through affiliate clicks or display ads. Your business model doesn’t require dialogue. Click-through rate and revenue per send matter more.

    But if you’re building toward courses, coaching, or any offer that requires trust, reply rate is the early indicator. It tells you who’s paying attention before you ask them to pay money.

    Start tracking reply rate this week. Create a spreadsheet. Column A: send date. Column B: delivered count. Column C: unique reply senders. Column D: reply rate. Update it after every send. If the number trends down over 8–10 emails, your content is drifting away from your audience.

    Want more tactical breakdowns like this? Subscribe to One Two Three Send and get one operator-focused article every day.

    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.

  • Course platform file upload limits and what happens at the boundary

    Course platform file upload limits and what happens at the boundary

    Course platform file upload limits and what happens at the boundary
    Photo: DS Pugh (CC BY-SA 2.0, via Wikimedia Commons)

    If you’ve ever uploaded a 2.1 GB course video to a platform with a 2 GB file limit, you know the frustration: some platforms reject it instantly, some let it upload for 45 minutes before failing, and some accept it but never process it.

    The boundary behavior—what happens when you hit or exceed a platform’s stated limit—varies wildly across course hosting tools. And because most operators don’t test edge cases until launch week, these differences cost time, bandwidth, and occasionally subscriber trust.

    Here’s what actually happens when you push the limits on three major platforms, and how to plan around their quirks.

    Teachable: hard stop at upload start

    Teachable enforces a 3 GB per-file limit for video uploads on all plans. If your file is 3.01 GB, the upload dialog won’t start. You’ll see an error message immediately: “File exceeds maximum size.”

    This is the cleanest failure mode. You know right away, before burning bandwidth or time. The downside: Teachable doesn’t compress or transcode client-side, so if your raw export is 3.2 GB, you need to re-encode it before upload. There’s no “let the platform handle it” option.

    Workaround: use Handbrake or similar to target H.264 at a slightly lower bitrate. For most 1080p talking-head content, 4 Mbps video gets you under 2.5 GB for a 90-minute lesson without visible quality loss.

    Kajabi: accepts upload, fails silently during processing

    Kajabi’s stated limit is 5 GB per file, but the real ceiling depends on your plan and whether you’re uploading via browser or the bulk uploader. On the Basic plan, files over 4 GB often upload successfully—progress bar completes—but then sit in “Processing” indefinitely.

    No error email. No dashboard alert. The file just never becomes available to students. If you don’t manually check back 12 hours later, you won’t know it failed.

    This is the worst failure mode for operators. You’ve burned upload time, you think the content is live, and students see a blank lesson or a spinner.

    Workaround: keep files under 3.5 GB even if your plan technically allows 5 GB. And always check the “Processed” timestamp in the library view before publishing a course.

    Thinkific: queues large files, then downgrades quality

    Thinkific’s limit is officially 5 GB, but files over 2 GB enter a slower processing queue. Upload completes normally, but transcoding can take 6–24 hours depending on platform load. During that window, students see a “Video is processing” message.

    Once processed, Thinkific applies adaptive bitrate streaming. But if your source file is large and high-bitrate, the platform may serve a lower-quality version to students on slower connections—even if you uploaded 1080p.

    This isn’t a failure, but it’s a surprise. Your 4K export might stream at 720p for 40% of viewers.

    Workaround: upload a clean 1080p H.264 file at 5–8 Mbps. That’s high enough for quality, low enough that Thinkific won’t aggressively downgrade. And schedule uploads at least 48 hours before launch.

    What about Vimeo or Wistia embeds?

    If you host video externally and embed it in your course platform, you bypass the platform’s file limits entirely. Vimeo Pro allows 20 GB per file; Wistia has no hard cap but recommends under 8 GB for optimal processing.

    The trade-off: you’re now managing two dashboards, two sets of analytics, and two potential points of failure. And some course platforms (Teachable included) don’t pass completion tracking reliably when you use third-party embeds. Students can watch the full video but the lesson won’t mark complete.

    This works well for operators who already have a Vimeo or Wistia account for other content, but it’s not a universal fix.

    One non-obvious tip: test with a disposable file first

    Before uploading your final course content, create a test file at exactly your platform’s stated limit plus 10%. Use a screen recording tool or export a low-content video at high bitrate to hit the target size.

    Upload it to a draft course. Wait 24 hours. Check if it processed, if quality degraded, if it triggered any backend errors.

    This takes 20 minutes and saves you from discovering boundary behavior during a launch.

    If you’re building a course business and want more operator-level breakdowns like this, subscribe to One Two Three Send—we cover the tooling details other newsletters skip.

  • Mailchimp migration exports: what gets lost in the CSV

    Mailchimp migration exports: what gets lost in the CSV

    Mailchimp migration exports: what gets lost in the CSV
    Photo: Mailchimp via Wikimedia Commons (CC BY-SA 4.0)

    If you’ve outgrown Mailchimp or decided to move to a platform with better economics, you’ll eventually hit the export button and download a CSV of your subscriber list. That file will contain email addresses, names, and maybe a few custom fields. What it won’t contain: most of the operational context that makes your list work.

    Mailchimp’s export is designed for portability, not fidelity. The platform strips out automation state, tag relationships, segment definitions, and engagement metadata that doesn’t fit neatly into a flat file. If you import that CSV into MailerLite, Beehiiv, or any other platform without documenting what’s missing, you’ll spend weeks rebuilding workflows from memory.

    Here’s what actually gets lost, and what you need to capture before you click export.

    Tags export as a single concatenated column

    Mailchimp allows unlimited tags per subscriber. When you export, all tags for a given contact collapse into one cell, separated by commas. That’s fine if you have three tags. It’s a disaster if you’ve been tagging behavior for two years.

    Most platforms expect tags as separate boolean columns (e.g., tag_buyer, tag_clicked_launch) or as a structured array. A comma-delimited string in one field rarely imports cleanly. You’ll need to split it manually or write a script.

    Worse: tag history disappears entirely. If someone was tagged “trial_user” in March and you removed it in June, the export only shows current state. That matters if your automations rely on timing—like sending a win-back email 90 days after a tag was removed.

    What to document: Export your full tag list separately (Audience → Manage contacts → Tags). Note which tags trigger automations, which are archival, and which represent states vs. actions. Screenshot your automation canvas if it’s complex.

    Segment logic doesn’t transfer

    Segments in Mailchimp are queries, not lists. A segment like “opened any email in the last 30 days AND has tag ‘premium’ AND joined before January 2026” is just a filter. When you export subscribers, you get a snapshot of who matched that query at export time—not the logic itself.

    If you’ve built segments for behavior-based targeting (e.g., engaged readers, cart abandoners, trial expirees), you’ll need to rebuild those rules manually in your new platform. Some platforms—like Beehiiv—have simpler segmentation tools. Others, like MailerLite, offer more flexibility but require you to map Mailchimp’s condition syntax to theirs.

    What to document: Go to Audience → Segments and export each segment definition as a screenshot or text file. Note the conditions, the subscriber count, and when you last used it. If a segment feeds an automation, flag that dependency.

    Automation subscriber state vanishes

    Mailchimp tracks where each subscriber sits in each automation: pending, completed, exited, paused. That state doesn’t export. If you’ve been running a five-email onboarding series and someone is on email three, your new platform has no idea. They’ll either get nothing or restart from email one.

    This is especially painful for evergreen sequences tied to signup date or product purchase. You can’t reconstruct who’s already received what unless you cross-reference campaign send logs—and those are buried in reporting, not in the subscriber export.

    What to document: Before migrating, go to Automations and note active workflows. For each one, export the workflow report showing how many people are in-progress. If possible, pause automations a week before migration so fewer people are mid-sequence. Consider sending a manual “reset” email post-migration to anyone who might have been interrupted.

    Custom field types sometimes downgrade

    Mailchimp supports text, number, date, dropdown, and address fields. Your export will contain the values, but not the field type. A date field becomes a string. A dropdown becomes plain text. A numeric rating becomes text unless you manually convert it.

    That matters if your new platform uses field types for segmentation or conditional content. MailerLite, for instance, lets you filter by “date is within the last 30 days”—but only if the field is recognized as a date type. If it imports as text, you lose that functionality until you re-type it and re-import.

    What to document: Go to Audience → Settings → Audience fields and merge tags. Screenshot the field list with types visible. When you import to your new platform, recreate fields with correct types before uploading the CSV. Map columns carefully during import.

    What you should do a week before migrating

    Don’t wait until export day to inventory your list. A week out, do this:

    • Pause any automations that would leave subscribers mid-sequence.
    • Export your full subscriber list, tag list, segment definitions, and custom field schema.
    • Download campaign reports for the last 90 days (opens, clicks, unsubscribes by campaign).
    • Document which integrations push data into Mailchimp (Shopify orders, Typeform signups, Stripe payments). You’ll need to reconnect those.
    • Check your sending domain’s DNS records. If you’ve been using Mailchimp’s dedicated sending domain, you’ll need to reconfigure DKIM and SPF for your new platform.

    If you’re moving to a platform like Beehiiv or MailerLite, both offer migration support—but “support” usually means they’ll import your CSV, not reconstruct your automations. The more you document upfront, the less you’ll have to rebuild from memory.

    One more thing: test with a small list first

    Before importing your full list, create a test audience in your new platform with 50–100 subscribers. Import that subset, rebuild one automation, and send a test campaign. Check that tags imported correctly, custom fields retained their types, and segments return expected counts. If something broke, fix it before migrating everyone.

    Most platforms let you delete and re-import without penalty during trial periods. Use that window.

    Want more tool migration guides? Reply with the platform you’re switching to—we’ll cover the gotchas specific to that move.

    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.

  • SEO title tags: character limits in 2026 and what gets truncated

    SEO title tags: character limits in 2026 and what gets truncated

    SEO title tags: character limits in 2026 and what gets truncated
    Photo by Lukas Müller on Unsplash

    Title tags still matter in 2026—they’re the clickable blue text in search results, the browser tab label, and the fallback headline when your content gets shared. But every platform truncates them differently, and most operators write titles blind, only discovering the cut-off after Google rewrites them or Twitter chops the last three words.

    Here’s what actually displays, where truncation happens, and how to structure titles so the important part survives everywhere.

    Character limits by platform in 2026

    Google Search displays roughly 55–60 characters on desktop, 50–55 on mobile. But it measures in pixels, not characters—specifically, around 600 pixels. That means uppercase letters, wide characters like ‘W’ and ‘M’, and em-dashes eat more space than lowercase ‘i’ or ‘l’. A 58-character title in all caps gets cut at word 6; the same count in sentence case displays fully.

    Bing allows slightly more room—around 65 characters—but rewrites titles more aggressively when it detects keyword stuffing or brand names it considers redundant.

    Social platforms are stricter. Twitter (yes, still called that in open graph parsers) cuts at 70 characters but only when the card is rendered; the meta tag itself has no hard limit. Facebook truncates around 60–65 characters in link previews. LinkedIn sits at 100 characters for article headlines but shortens page titles to roughly 60 in shares.

    Email clients display title tags in ‘view in browser’ links and when newsletters embed web content. Gmail renders about 70 characters in the browser tab, Outlook around 50.

    What gets truncated—and what vanishes entirely

    Most CMS plugins and SEO tools place the site name at the end of every title, separated by a pipe or dash. That’s fine—until truncation cuts the entire descriptive phrase and leaves only your brand. Google’s algorithm now ignores the visible title in cases where it decides the cut version is uninformative, pulling replacement text from your H1, meta description, or even anchor text pointing to the page.

    Operators lose control when the replacement text doesn’t match search intent. A title like “WordPress Object Cache Configuration | YourSite” might display as “WordPress Object Cache Configuration” on desktop but just “WordPress Object…” on mobile. Google may rewrite it to “How to Configure Object Cache in WordPress—YourSite,” pulling from your intro paragraph.

    Numbers, colons, and em-dashes create natural break points. Titles structured as “Primary Keyword: Secondary Detail” survive truncation better than run-on sentences. The colon signals to rendering engines that everything before it is the core message.

    Front-load the hook, back-load the context

    The first 40–45 characters are safe everywhere. Use them for the primary keyword and the specific angle. Save brand names, dates, and supplementary phrases for the tail.

    Compare:
    “Email deliverability tips for SaaS companies in 2026—YourSite”
    vs.
    “SaaS email deliverability: what changed in 2026 | YourSite”

    The second version survives mobile truncation with the core message intact. The first cuts to “Email deliverability tips for SaaS comp…”—losing both the year and the site name, and looking like generic advice.

    If your site name is long, drop it from title tags on inner pages. Google appends it automatically in 60% of cases anyway, pulling from your homepage title or site identity settings. You’re better off using those 15 characters for a stronger hook.

    Test truncation before you publish

    Most SEO plugins show a preview, but they assume average character width. If your titles use uncommon punctuation, all-caps brand names, or UTF-8 symbols, test in a real SERP simulator.

    Free tools like Portent’s SERP Preview and Yoast’s snippet editor render titles in Google’s actual display font (Roboto on desktop, system sans-serif on mobile). Run your title through both before committing.

    For operators publishing at volume—daily blog posts, newsletter archives, product landing pages—set a template that front-loads keywords and makes the site name optional. Most WordPress themes let you customize title structure per post type. Use %%title%% | %%sitename%% for long-form content, %%title%% for time-sensitive posts where every character counts.

    When Google rewrites your title anyway

    Even a perfectly-sized title gets rewritten if Google decides it doesn’t match the query. In 2026, title rewrites happen in roughly 60% of organic impressions—up from 50% two years ago. The algorithm pulls from your H1, meta description, or visible page content when it believes those better answer the searcher’s intent.

    You can’t prevent rewrites entirely, but you can reduce them. Match your title tag to your H1. Avoid keyword-stuffed lists or promotional language in the title. If Google rewrites consistently for a high-traffic page, check Search Console’s ‘Page experience’ report—it sometimes flags titles as ‘not descriptive’ when they’re too vague or too sales-heavy.

    Truncation isn’t a ranking factor, but a truncated title that confuses users does hurt click-through rate—and CTR is a ranking signal. Structure your titles so the most important words display everywhere, even when platforms cut the rest.

    One Two Three Send covers traffic, tools, and operations for online-business builders. Subscribe for tactics like this every week.