Tools
Setu exposes six tools. Your assistant decides when to call them — you never invoke these by hand.
get_my_profile
Who you are, your role, saved link, plan, and remaining quota. The assistant should call this first — everything else depends on it.
Input
None.
Returns
email, name, role, link, link_saved, link_required, plan, subscribed_at, subscription_ends_at, total_sent, free_remaining, sent_last_24h, daily_limit, remaining_today, setup_needed
Example
{
"email": "you@gmail.com",
"name": "Himanshu Yadav",
"role": "job_seeker",
"role_label": "Job seeker",
"link": "https://drive.google.com/file/d/…",
"link_label": "Resume",
"link_saved": true,
"link_required": true,
"plan": "free",
"total_sent": 3,
"free_email_limit": 5,
"free_remaining": 2,
"sent_last_24h": 3,
"daily_limit": 80,
"remaining_today": 77,
"setup_needed": null
}set_role
Sets what the user does — job_seeker, recruiter, or professional. The role decides what link rides along with their emails and whether one is required at all. Ask the user; never infer it. Changeable any time.
Input
| Name | Type | Required | Description |
|---|---|---|---|
role | string | yes | job_seeker | recruiter | professional |
Returns
success, role, role_label, link_label, link_required, next_step
Example
{
"success": true,
"role": "recruiter",
"role_label": "Recruiter",
"link_label": "Job description",
"link_required": false,
"next_step": "Optional: ask if they want a job description
link on their emails."
}save_link
Saves the URL appended to every email. What it is depends on the role — a resume for a job seeker, a job description for a recruiter, a portfolio for a professional. Setu fetches it to check the recipient could actually open it, so a private Drive file is rejected here rather than silently failing in someone's inbox.
Input
| Name | Type | Required | Description |
|---|---|---|---|
link | string | yes | Public http(s) URL — Drive, Dropbox, personal site |
Returns
success, link, link_label, detail — or an error explaining the rejection
Example
{
"success": false,
"error": "This link is not shared publicly — it redirects to a
sign-in page, so the recipient would see 'Request access'
instead of the file. Open it in Drive, click Share, and set
'Anyone with the link' to Viewer.",
"link": "https://drive.google.com/file/d/…"
}verify_hr_emails
Advisory. Checks whether an address's domain can actually receive mail, and flags addresses that look constructed from a naming pattern rather than found on a page. Does not block sending unless VERIFY_HR_EMAILS is enabled on the server.
Input
| Name | Type | Required | Description |
|---|---|---|---|
candidates | Candidate[] | yes | Each: email, company, source_url (the page you saw it on) |
Returns
checked, usable, rejected, results[] with reasons and warnings
Example
{
"checked": 2,
"usable": 1,
"rejected": 1,
"results": [
{ "email": "careers@acme.com", "ok": true,
"detail": "MX: aspmx.l.google.com" },
{ "email": "hr@acme-inc.io", "ok": false,
"reasons": ["acme-inc.io: domain does not exist"] }
]
}send_application
irreversibleSends one email from your Gmail — any email, not only applications: meeting requests, follow-ups, greetings. Irreversible. Refuses if no role is set, if the role needs a link and none is saved, if the free allowance is spent, or if the daily limit is reached. Your link is appended by default; include_link=false leaves it off.
Input
| Name | Type | Required | Description |
|---|---|---|---|
to | string | yes | Recipient address |
subject | string | yes | Subject line |
body | string | yes | Plain text body |
company | string | no | For your history |
source_url | string | no | Where the address came from |
include_link | bool | no | Default true. false = don't append your saved link (general messages) |
Returns
success, to, subject, message_id — or success:false with error
Example
{
"success": true,
"to": "careers@acme.com",
"subject": "Application for Backend Engineer at Acme",
"message_id": "18f2a9c4d5e6b7a8"
}send_applications
irreversibleSends a batch of emails — applications or any other kind — pausing between each so Gmail doesn't read the run as automated. Capped at 25 per call, so you review as you go instead of finding out afterwards.
Input
| Name | Type | Required | Description |
|---|---|---|---|
applications | Application[] | yes | Each: to, subject, body, company, source_url — max 25 |
delay_seconds | int | no | Pause between sends. Defaults to the server's EMAIL_DELAY (5s) |
include_link | bool | no | Default true. false = don't append your saved link to any message in the batch |
Returns
sent, failed, skipped, skipped_details[], results[], remaining_today
Example
{
"success": true,
"sent": 8,
"failed": 0,
"skipped": 1,
"skipped_details": [
{ "to": "hr@x.com", "reason": "daily limit reached" }
],
"remaining_today": 60
}get_sent_history
Everything you've sent through Setu, newest first. The record survives across sessions, which is what makes duplicate-send prevention possible.
Input
| Name | Type | Required | Description |
|---|---|---|---|
limit | int | no | How many rows. Default 20 |
Returns
sent_last_24h, daily_limit, entries[]
Example
{
"sent_last_24h": 12,
"daily_limit": 80,
"entries": [
{ "to_email": "careers@acme.com", "company": "Acme",
"success": true, "message_id": "18f2a9c4d5e6b7a8",
"sent_at": "2026-07-15T09:22:04+00:00" }
]
}