
What it does
I paste a job post into a chat channel, as text or a screenshot. About 30 seconds later a thread shows who it will go to, the subject, which CV was picked and why, the email and the cover letter as a PDF. I can change the recipient, ask for a rewrite ("shorter", "mention the Go projects"), or press Send. Then it goes out from my Gmail with the CV and the cover letter attached.
The model reads, the code decides
- The email address. The model pulls it out of the post, then code checks it is a real address and that it appears in the post word for word. One that does not is flagged; one read from a screenshot is flagged so I check the spelling; a post with no email cannot be sent at all.
- The CV. I keep 24 CVs, each with a focus in its file name (agentic-rag, healthcare-saas, mobile-saas-ai-payments...). Code maps the job's words onto those focus tags, counts a focus named in the role title twice, and shows the reason. A React Native post gets the mobile CV even when it also mentions APIs.
- What gets sent. Sending is its own request that must name the draft. The same role to the same address is refused, there is a daily cap, and the check, the send and the record happen under one lock, so a double tap sends once.
Honest letters
The letter may only use facts from my profile and project catalog. It follows applicant instructions in the post, such as a subject code. When the post asks for something I have not done, it says so plainly and points to the closest real work, as in the sample: "I have not used LangGraph or pgvector in production yet, but I have built the same patterns by hand."
Three ways in
A Discord bot thread for daily use, an n8n form that calls the same API, and the HTTP API itself. The AI runs through the Claude Code or Codex command line already signed in on the machine, so there is no API key, and if one runs out of usage the other answers.
Tested
Unit tests run the whole API against a fake model and a fake mail server: creating a draft never sends mail, sending needs the confirm field, both PDFs are attached, a second tap and a duplicate application are refused, the daily cap holds, and a made-up address is not marked as verified. It was also run for real on three sample posts, including a screenshot, with my real CVs and profile.
Stack
Go 1.27, Gmail SMTP with an app password, go-pdf for the cover letter, Claude Code and Codex CLIs, a Python Discord bot, n8n. Code: github.com/shabeebhasan/applymail-go.
What it does not claim
It does not apply through LinkedIn itself and does not read LinkedIn pages; I paste the post. It only helps where a post gives an email address. The n8n workflow is included but has not yet been run on an n8n instance.