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
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