Part 4 of 7 · Social scheduler series ~5 min read

How a post gets formatted per channel

The scheduler said send. Now the Sender Lambda has to figure out which channels this post is headed to, whether the text and image fit each one’s rules, whether the channel token still works, and only then post it. Get any of those wrong and the post is worse than no post: a caption chopped off mid-word, an image the platform silently dropped, a link that broke the layout. Four small guardrails sit between the send move and the post actually landing.

Key takeaways

  • Channel resolution: per-post channel list beats the account default beats a safe fallback.
  • Text is checked against each channel’s character limit and link count before anything goes out.
  • Images are checked for size and type each channel accepts; a bad image fails the post, not silently.
  • The channel token is checked for freshness; a stale token is refreshed before the send.
  • A post that fails any check is flagged back to the owner with the exact reason instead of being sent.

Four guardrails on every send

Four guardrails between the scheduler's send move and the posted message A horizontal flow diagram. On the far left, a "Send move" box: the scheduler emitted an event with the post, its channels, and the move to send now. Four guardrail gates sit in a row to the right, each drawn as a vertical bar. Gate 1: Resolve channels — reads the per-post channel list first; if blank, falls back to the account default channels from the rules doc; if still blank, falls back to a single safe channel. Returns the channel list with each channel's posting endpoint. Gate 2: Format check — checks the text against each channel's character limit and link count from the rules doc, trims trailing whitespace, and verifies the post is not empty; a post that overruns a limit fails with the exact count. Gate 3: Image and token — checks the linked image's size and type against what each channel accepts, fetching it from S3; checks the channel token from Secrets Manager is still valid and refreshes it if it is near expiry; a missing or oversized image fails the post. Gate 4: Compose and send — builds the final per-channel payload, posts to each channel through its posting endpoint, and collects the live post link or the error per channel. After all four gates pass, the post ships to each chosen channel and the result is recorded. A note at the bottom: a post that fails any gate is flagged to the owner with the reason — it is never sent half-broken. Send move post, channels, send now from scheduler Gate 1 Resolve channels post list? account default? safe fallback? map each to its posting endpoint Gate 2 Format check text within char limit? link count ok, not empty; else flag owner Gate 3 Image and token image size and type ok? token fresh? refresh if near expiry Gate 4 Compose + send build payload per channel post to each, collect link or error Posted — to each chosen channel, with a live link recorded per channel post via each channel’s posting endpoint · image from S3 every send logged to DDB ss-sends — the report knows what landed A post that fails any gate is flagged to the owner with the reason — it is never sent half-broken.
Fig 4. Four guardrails between the send move and the posted message. Resolve the channels. Check the text. Check the image and token. Compose and send. Then post to each channel and log the result so the report knows what landed.

Gate 1: resolve the channels

Three places the Sender looks for the channels of a post, in order. First, the sheet’s per-post channels column — if a row names specific channels, those are the ones, regardless of the account default. Second, the account-default channel list in the rules doc (“every post goes to Facebook and Instagram unless told otherwise”). Third, a single safe fallback channel — usually the main page — so a post with a blank channel cell still has somewhere to go rather than failing silently.

Once the Sender knows which channels to post to, it maps each one to its posting endpoint and the token that authorizes it. The token for each channel lives in Secrets Manager. Different platforms have different posting interfaces, but from the Sender’s point of view each channel is just “an endpoint plus a token plus a set of format rules.”

Gate 2: format check

The rules doc lists the format limits for each platform: the maximum character count for the text, the maximum number of links the platform renders cleanly, and any required fields. Gate 2 checks the post’s text against the limits for every chosen channel. A caption that fits Facebook but overruns Instagram fails for Instagram with the exact count — “caption is 2,310 characters; Instagram’s limit is 2,200” — rather than being chopped off when it posts.

A post that fails the format check isn’t sent. Instead the Sender writes the failure to the post’s status with the reason, and the owner gets a flag: “This post is too long for Instagram. Shorten it or drop Instagram from the channel list.” The post goes back to draft and waits for a fix. Catching the problem before the send beats catching it after, when the truncated post is already public.

Gate 3: image and token

If the post has an image, Gate 3 fetches it from S3 (the drive-sync Lambda mirrored it there from the Drive folder) and checks its size and type against what each chosen channel accepts. Platforms reject images that are too small, too large, or in a format they don’t support — and they often do it silently, posting the text with no picture. Gate 3 turns that silent failure into an explicit one: a bad image fails the post with the reason, so the owner can swap it before anything goes out.

Gate 3 also checks the channel token. Social tokens expire. If a token is close to expiry, the Sender refreshes it (using the refresh credential in Secrets Manager) before the send, so a post never fails just because a token lapsed overnight. If a token can’t be refreshed — the account was disconnected, the password changed — the post fails with “the Facebook connection needs to be re-linked,” which is a fixable, clear message rather than a mystery.

Gate 4: compose and send

With the channels resolved, the text checked, and the image and token verified, Gate 4 builds the final payload for each channel — the text sized for that platform, the image attached, any required fields filled — and posts it through that channel’s posting endpoint. Each channel is posted independently, so if Facebook succeeds and Instagram briefly times out, the success on Facebook still counts and only Instagram is queued for a retry.

For each channel, the Sender collects either the live post link (on success) or the error message (on failure) and writes a row to ss-sends in DynamoDB. That row is what the report reads: “Tuesday offer — posted to Facebook [link], posted to Instagram [link].” A failure shows up the same way with the reason, so the owner always knows exactly what happened.

Why the guardrails exist

None of these gates are exotic. They’re the kind of small care a thoughtful person would take if they were posting by hand — check it’s going to the right places, make sure it fits, make sure the picture works, then post it and grab the link. Putting them in code as four small sequential gates makes them part of the design, not a feature you’re trusting the writer of any one post to remember at 9am.

Next post: how a post gets approved or held once it’s in the queue — the three actions on the Review button and how the sheet, the status, and the audit trail stay in sync.

All posts