From bulk-messenger
This skill should be used when the user asks to "send messages to my contacts", "send bulk SMS", "message multiple people", "send personalized messages", "text everyone", or wants to send SMS messages to multiple recipients using templates.
How this skill is triggered — by the user, by Claude, or both
Slash command
/bulk-messenger:send-messagesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Send personalized SMS messages to multiple contacts using templates with variable placeholders.
Send personalized SMS messages to multiple contacts using templates with variable placeholders.
This skill guides users through creating a bulk message campaign by collecting two critical pieces of data and then confirming the campaign with the user: 1) Submit the list of contact recipients - with 'phone_number' being the only required field, 2) Submit the message to send (with customized variables), and 3) Give a preview of the campaign. After the user has confirmed, the skill will send the message individually to every recipient.
For interactive composition, this skill uses the web-builder skill to generate self-contained HTML artifacts that the user interacts with. The user then copies the output and pastes it back to Claude for parsing.
Ask the user provide their contact list. They can paste text in the chat, attach files with contacts, or connect to any data source.
Tell the user they can provide contacts in any format as long as each record includes a phone number:
"Please provide your contact list. You can use:
CSV format:
phone_number,name,company +15551234567,John,Acme Corp +15559876543,Sarah,Tech IncJSON format:
[ {"phone_number": "+15551234567", "name": "John", "company": "Acme Corp"}, {"phone_number": "+15559876543", "name": "Sarah", "company": "Tech Inc"} ]Or simple list:
+15551234567 John Acme +15559876543 Sarah TechOnly
phone_numberis required. Any additional fields can be used as template variables."
Wait for the user to provide their contact data, then parse it.
Parse and Store the contact list to use in the messaging workflow.
Ask the user how they want to provide their message template:
{
"questions": [
{
"id": "template-method",
"prompt": "How would you like to compose your message template?",
"options": [
{
"id": "Quick",
"label": "Quick - Type it in chat"
},
{
"id": "Interactive",
"label": "Interactive - Use visual composer"
}
]
}
]
}
Tell the user how to submit their message:
"Please provide your message template. Use double curly braces for variables:
{{variable_name}}Example:
Hi {{name}}, just checking in about {{topic}}. Let me know if you need anything!Common variables:
{{name}}- Recipient's name{{first_name}}- First name only{{company}}- Company name{{date}}- Date- Any custom variable you need"
Wait for the user to provide their template text.
Use the web-builder skill to build an interactive SMS composer:
templates/sms-composer.md templateWhen the user pastes the output, it will be natural language like:
"I've composed an SMS message. The message is: 'Hi {{name}}, happy holidays from {{company}}! Enjoy {{discount}}% off.'"
Parse this output to extract:
Store the template message Store the message to use in the messaging workflow
After collecting both the message and contact list, show a preview of the bulk message campaign you have prepared:
For the first 3 recipients:
{{variable}} with the recipient's valueExample:
Template: Hi {{name}}, checking in about {{topic}}
Recipient: {"name": "John", "topic": "project"}
Result to show the user: Hi John, checking in about project
Then offer the user a visual preview:
{
"questions": [
{
"id": "preview-method",
"prompt": "Would you like to preview your message and recipients before sending?",
"options": [
{
"id": "interactive",
"label": "Yes - Open visual preview"
},
{
"id": "skip",
"label": "No - Proceed to send"
}
]
}
]
}
Use the web-builder skill to build a message preview:
templates/preview.md templateWhen the user pastes the output, it will include edits to the bulk messaging campaign, or direction to proceed. Edit campaign (if necessary).
This flow confirms the user has reviewed and approved all messages. Proceed to sending.
Skip to Step 4 (Validate Phone Numbers).
For each phone number:
Valid formats:
5551234567 (10 digits, US)+15551234567 (international format)555-123-4567 (will be cleaned to 5551234567)If invalid: Report which phone numbers are invalid and ask user to correct.
For each recipient:
{{variable}} with the recipient's valueExample:
Template: Hi {{name}}, checking in about {{topic}}
Recipient: {"name": "John", "topic": "project"}
Result: Hi John, checking in about project
Variable replacement algorithm:
import re
def personalize_message(template, recipient_data):
message = template
variables = re.findall(r'\{\{([^}]+)\}\}', template)
for var in variables:
var_clean = var.strip()
if var_clean in recipient_data:
message = message.replace(f'{{{{{var}}}}}', str(recipient_data[var_clean]))
else:
message = message.replace(f'{{{{{var}}}}}', f'[MISSING: {var_clean}]')
return message
Display all personalized messages for user review:
Preview (3 messages):
1. To: John (+15551234567)
Message: Hi John, checking in about project
2. To: Sarah (+15559876543)
Message: Hi Sarah, checking in about meeting
3. To: Mike (+15555551234)
Message: [full message shown]
Ask for confirmation: "Ready to send these messages?"
For each recipient, use AppleScript to send via Messages.app:
AppleScript command:
osascript -e 'tell application "Messages"
set targetService to 1st account whose service type = iMessage
set targetBuddy to participant "[PHONE]" of targetService
send "[MESSAGE]" to targetBuddy
end tell'
Implementation steps:
Error handling:
Note for Claude Desktop VM: If running in Claude Desktop's VM environment and Messages.app is not accessible, offer an alternative output format:
Messages.app is not accessible in this environment. Here are your personalized messages ready to send manually:
1. +15551234567 (John)
Hi John, checking in about project
2. +15559876543 (Sarah)
Hi Sarah, checking in about meeting
[Copy and send these manually through Messages.app]
After sending all messages (or providing the manual list), display a summary:
If sent successfully:
SMS Campaign Complete!
Sent: 3 messages
Failed: 0
All messages sent via Messages.app.
If any failures:
SMS Campaign Complete!
Sent: 2 messages
Failed: 1 (Mike - Messages.app error)
Review failed messages and retry if needed.
If manual output provided:
SMS Campaign Prepared!
Generated: 3 personalized messages
Messages are ready to send manually via Messages.app.
Ask the user if they would like save any records:
{
"questions": [
{
"id": "Save Rercords?",
"prompt": "Would you like to save any data from this campaign?",
"options": [
{
"id": "Message Template",
"label": "Markdown file of the message template"
},
{
"id": "Activity Log",
"label": "JSON file of the message template & contact recipients"
},
{
"id": "skip",
"label": "Nope - End the workflow"
}
]
}
]
}
If the user selects Message Template Create a markdown file of the message template used in the bulk message campaign and put it in the /output folder, including a simple timestamp in the filename.
IF the user selects Activity Log Create a json file with two objects: 1) the message template used, and 2) the contacts, including any metadata or additional fields in the contact record. Put this json file in the ouput folder, including a simple timestamp in the filename.
BEFORE YOU END THIS SKILL & regardless of whether the user completed the workflow, always delete any *.html files that were created during this session. Check both the plugin root output/ folder and the session's /sessions/[session-id]/mnt/outputs/ folder. Do not delete any other files besides html pages.
Professional Demeanor
Messages.app requirements:
Privacy:
Rate limiting:
Error scenarios:
Claude Desktop VM Limitations:
Messages don't send:
Variables not replacing:
Web builder artifacts not opening:
skills/web-builder/templates/Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub betoiii/betos-plugin-marketplace --plugin bulk-messenger