Letter Writer by jmsktm/claude-settings
npx skills add https://github.com/jmsktm/claude-settings --skill 'Letter Writer'信件撰写器技能可自动创建格式规范、语气恰当、结构合理的专业和个人信件。它处理各种信件类型,包括商务信函、求职信、推荐信、感谢信和正式通信。该技能确保为不同受众和目的提供适当的格式、专业语言和定制化服务。
生成多种格式(PDF、DOCX、HTML)的信件,并针对不同场合和通信需求提供可自定义的模板。
目的: 为特定职位申请创建具有吸引力的定制求职信
步骤:
实现:
const { Document, Packer, Paragraph, AlignmentType, TextRun } = require('docx');
const fs = require('fs');
async function generateCoverLetter(letterData, outputPath) {
const doc = new Document({
sections: [{
properties: {
page: {
margin: {
top: 1440, // 1 inch
right: 1440,
bottom: 1440,
left: 1440
}
}
},
children: [
// Your contact information
new Paragraph({
text: letterData.sender.name,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.sender.address,
spacing: { after: 0 }
}),
new Paragraph({
text: `${letterData.sender.city}, ${letterData.sender.state} ${letterData.sender.zip}`,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.sender.email,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.sender.phone,
spacing: { after: 200 }
}),
// Date
new Paragraph({
text: new Date().toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
}),
spacing: { after: 200 }
}),
// Recipient information
new Paragraph({
text: letterData.recipient.name || 'Hiring Manager',
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.company,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.address,
spacing: { after: 0 }
}),
new Paragraph({
text: `${letterData.recipient.city}, ${letterData.recipient.state} ${letterData.recipient.zip}`,
spacing: { after: 200 }
}),
// Salutation
new Paragraph({
text: `Dear ${letterData.recipient.name || 'Hiring Manager'}:`,
spacing: { after: 200 }
}),
// Opening paragraph
new Paragraph({
text: `I am writing to express my strong interest in the ${letterData.position} position at ${letterData.recipient.company}. ${letterData.opening}`,
alignment: AlignmentType.JUSTIFIED,
spacing: { after: 200 }
}),
// Body paragraphs
...letterData.bodyParagraphs.map(para =>
new Paragraph({
text: para,
alignment: AlignmentType.JUSTIFIED,
spacing: { after: 200 }
})
),
// Closing paragraph
new Paragraph({
text: letterData.closing || `Thank you for considering my application. I am excited about the opportunity to contribute to ${letterData.recipient.company} and would welcome the chance to discuss how my skills and experience align with your needs. I look forward to hearing from you.`,
alignment: AlignmentType.JUSTIFIED,
spacing: { after: 200 }
}),
// Signature
new Paragraph({
text: 'Sincerely,',
spacing: { after: 400 }
}),
new Paragraph({
text: letterData.sender.name
})
]
}]
});
const buffer = await Packer.toBuffer(doc);
fs.writeFileSync(outputPath, buffer);
return outputPath;
}
// Helper function to generate body paragraphs based on job requirements
function generateCoverLetterBody(candidateData, jobData) {
const paragraphs = [];
// Experience paragraph
const relevantExperience = candidateData.experience
.filter(exp => exp.relevanceScore > 0.7)
.slice(0, 2);
if (relevantExperience.length > 0) {
const expText = `With ${calculateYearsExperience(candidateData.experience)} years of experience in ${jobData.industry}, I have developed strong expertise in ${jobData.keySkills.slice(0, 3).join(', ')}. In my current role at ${relevantExperience[0].company}, ${relevantExperience[0].achievements[0].toLowerCase()}`;
paragraphs.push(expText);
}
// Skills and qualifications paragraph
const matchingSkills = candidateData.skills
.filter(skill => jobData.requiredSkills.includes(skill.name))
.slice(0, 4);
if (matchingSkills.length > 0) {
const skillsText = `I am particularly well-suited for this role given my proficiency in ${matchingSkills.map(s => s.name).join(', ')}. ${candidateData.achievements.find(a => a.includes(matchingSkills[0].name)) || 'I have successfully applied these skills to deliver measurable results.'}`;
paragraphs.push(skillsText);
}
// Company-specific paragraph
if (jobData.companyInfo) {
const companyText = `I am particularly drawn to ${jobData.company} because of ${jobData.companyInfo.appeal || 'your reputation for innovation and excellence'}. I believe my background in ${jobData.relevantBackground} would enable me to make immediate contributions to your team.`;
paragraphs.push(companyText);
}
return paragraphs;
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
目的: 使用适当格式创建正式的商务信函
步骤:
实现:
async function generateBusinessLetter(letterData, outputPath) {
const letterTypes = {
inquiry: {
subject: 'Inquiry Regarding',
opening: 'I am writing to inquire about',
tone: 'polite and professional'
},
complaint: {
subject: 'Concern Regarding',
opening: 'I am writing to bring to your attention',
tone: 'firm but professional'
},
proposal: {
subject: 'Proposal for',
opening: 'I am pleased to present',
tone: 'professional and enthusiastic'
},
thankyou: {
subject: 'Thank You',
opening: 'I wanted to express my sincere gratitude for',
tone: 'warm and appreciative'
}
};
const template = letterTypes[letterData.type] || letterTypes.inquiry;
const doc = new Document({
sections: [{
properties: {
page: {
margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }
}
},
children: [
// Company letterhead (if provided)
...(letterData.letterhead ? [
new Paragraph({
text: letterData.letterhead.companyName,
alignment: AlignmentType.CENTER,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.letterhead.address,
alignment: AlignmentType.CENTER,
spacing: { after: 0 }
}),
new Paragraph({
text: `${letterData.letterhead.phone} | ${letterData.letterhead.email}`,
alignment: AlignmentType.CENTER,
spacing: { after: 400 }
})
] : []),
// Date
new Paragraph({
text: new Date().toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
}),
spacing: { after: 200 }
}),
// Recipient
new Paragraph({
text: letterData.recipient.name,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.title,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.company,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.address,
spacing: { after: 200 }
}),
// Subject line
...(letterData.subject ? [
new Paragraph({
children: [
new TextRun({ text: 'RE: ', bold: true }),
new TextRun(letterData.subject)
],
spacing: { after: 200 }
})
] : []),
// Salutation
new Paragraph({
text: `Dear ${letterData.recipient.name}:`,
spacing: { after: 200 }
}),
// Body
...letterData.paragraphs.map(para =>
new Paragraph({
text: para,
alignment: AlignmentType.JUSTIFIED,
spacing: { after: 200 }
})
),
// Closing
new Paragraph({
text: letterData.closing || 'Sincerely,',
spacing: { after: 400 }
}),
// Signature
new Paragraph({
text: letterData.sender.name,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.sender.title
})
]
}]
});
const buffer = await Packer.toBuffer(doc);
fs.writeFileSync(outputPath, buffer);
return outputPath;
}
目的: 为员工、学生或同事创建推荐信
步骤:
实现:
function generateRecommendationLetter(recommendationData) {
const letterData = {
sender: recommendationData.recommender,
recipient: recommendationData.recipient || {
name: 'To Whom It May Concern'
},
type: 'recommendation',
paragraphs: [
// Opening - establish relationship
`I am writing to enthusiastically recommend ${recommendationData.candidate.name} for ${recommendationData.purpose}. I have had the pleasure of working with ${recommendationData.candidate.firstName} for ${recommendationData.duration} in my capacity as ${recommendationData.recommender.title} at ${recommendationData.recommender.company}.`,
// Qualifications and strengths
`During our time working together, ${recommendationData.candidate.firstName} has consistently demonstrated exceptional ${recommendationData.strengths.join(', ')}. ${recommendationData.standoutQualities}`,
// Specific examples
...recommendationData.examples.map(example =>
`For instance, ${example.description} This ${example.impact}`
),
// Comparison to peers (if applicable)
...(recommendationData.comparison ? [
`${recommendationData.candidate.firstName} stands out among ${recommendationData.comparison.peerGroup} for ${recommendationData.comparison.distinguishingFactors}.`
] : []),
// Strong endorsement
`I am confident that ${recommendationData.candidate.firstName} will be an outstanding ${recommendationData.targetRole} and will bring the same level of dedication, skill, and enthusiasm that I have witnessed firsthand. ${recommendationData.candidate.pronoun} has my highest recommendation without reservation.`,
// Offer additional information
`Please feel free to contact me at ${recommendationData.recommender.phone} or ${recommendationData.recommender.email} if you would like to discuss ${recommendationData.candidate.firstName}'s qualifications further.`
]
};
return generateBusinessLetter(letterData, recommendationData.outputPath);
}
目的: 为各种场合创建专业的感谢信
步骤:
实现:
function generateThankYouLetter(thankYouData) {
const templates = {
interview: {
opening: `Thank you for taking the time to meet with me ${thankYouData.when} to discuss the ${thankYouData.position} position at ${thankYouData.company}.`,
body: `I enjoyed learning more about ${thankYouData.discussionTopics} and was particularly excited to hear about ${thankYouData.highlight}. Our conversation reinforced my strong interest in joining your team and contributing to ${thankYouData.contribution}.`,
closing: `I am very enthusiastic about this opportunity and believe my ${thankYouData.relevantSkills} would be a strong fit for your needs. Thank you again for your time and consideration. I look forward to hearing from you.`
},
meeting: {
opening: `Thank you for meeting with me on ${thankYouData.date} to discuss ${thankYouData.topic}.`,
body: `I found our conversation about ${thankYouData.keyPoints} very valuable. Your insights regarding ${thankYouData.insight} gave me a new perspective on ${thankYouData.subject}.`,
closing: `I appreciate your time and expertise. I look forward to our continued collaboration.`
},
gift: {
opening: `Thank you so much for the thoughtful ${thankYouData.gift}.`,
body: `Your generosity and thoughtfulness are greatly appreciated. ${thankYouData.personalNote}`,
closing: `Thank you again for thinking of me. Your kindness means a lot.`
},
networking: {
opening: `It was a pleasure meeting you at ${thankYouData.event} on ${thankYouData.date}.`,
body: `I enjoyed our conversation about ${thankYouData.topic} and found your perspective on ${thankYouData.insight} particularly interesting. I would love to stay connected and explore opportunities for ${thankYouData.futureCollaboration}.`,
closing: `Thank you for taking the time to speak with me. I've connected with you on LinkedIn and look forward to staying in touch.`
}
};
const template = templates[thankYouData.type] || templates.meeting;
return {
sender: thankYouData.sender,
recipient: thankYouData.recipient,
subject: `Thank you - ${thankYouData.regarding}`,
paragraphs: [
template.opening,
template.body,
template.closing
],
closing: 'Best regards,'
};
}
目的: 从模板和数据源创建多个个性化信件
步骤:
实现:
const Handlebars = require('handlebars');
async function batchGenerateLetters(templatePath, recipientsData, outputDir) {
const template = fs.readFileSync(templatePath, 'utf8');
const compiledTemplate = Handlebars.compile(template);
const results = [];
for (const recipient of recipientsData) {
try {
// Merge recipient data with template
const letterContent = compiledTemplate(recipient);
// Generate filename
const filename = `${outputDir}/letter-${recipient.id}-${recipient.name.replace(/\s+/g, '-')}.docx`;
// Create letter data
const letterData = {
sender: recipient.sender || recipientsData.defaultSender,
recipient: {
name: recipient.name,
title: recipient.title,
company: recipient.company,
address: recipient.address
},
paragraphs: letterContent.split('\n\n').filter(p => p.trim()),
subject: recipient.subject
};
// Generate letter
await generateBusinessLetter(letterData, filename);
results.push({
success: true,
recipientId: recipient.id,
name: recipient.name,
filename: filename
});
} catch (error) {
results.push({
success: false,
recipientId: recipient.id,
name: recipient.name,
error: error.message
});
}
}
// Generate summary report
const summary = {
total: recipientsData.length,
successful: results.filter(r => r.success).length,
failed: results.filter(r => !r.success).length,
results: results
};
fs.writeFileSync(
`${outputDir}/batch-summary.json`,
JSON.stringify(summary, null, 2)
);
return summary;
}
| 操作 | 命令/触发器 |
|---|---|
| 求职信 | "write cover letter for [position]" |
| 商务信函 | "create business letter to [recipient]" |
| 推荐信 | "generate recommendation letter" |
| 感谢信 | "write thank you letter" |
| 正式信函 | "draft formal correspondence" |
| 批量信件 | "create letters for [recipients]" |
职位申请包:
{
coverLetter: generateCoverLetter(candidateData, jobData),
resume: generateResume(candidateData),
references: generateReferencesList(candidateData.references)
}
客户服务响应:
{
type: 'response',
tone: 'apologetic and solution-oriented',
structure: ['acknowledge issue', 'explain what happened', 'describe resolution', 'offer compensation', 'prevent future']
}
安装所需包:
npm install docx
npm install handlebars # For templating
npm install pdf-lib # For PDF generation
npm install nodemailer # For email sending (optional)
电子邮件集成:
async function sendLetter(letterPath, recipientEmail, subject) {
const transporter = nodemailer.createTransporter(config);
await transporter.sendMail({
from: senderEmail,
to: recipientEmail,
subject: subject,
html: '<p>Please find attached letter.</p>',
attachments: [{ path: letterPath }]
});
}
签名集成:
async function addDigitalSignature(letterPath, signatureImagePath) {
// Add scanned signature image to letter
// Position at signature block
}
模板库:
const letterTemplates = {
coverLetter: './templates/cover-letter.hbs',
businessInquiry: './templates/business-inquiry.hbs',
recommendation: './templates/recommendation.hbs',
thankYou: './templates/thank-you.hbs'
};
每周安装
–
仓库
GitHub 星标数
2
首次出现
–
安全审计
The Letter Writer skill automates the creation of professional and personal letters with proper formatting, tone, and structure. It handles various letter types including business correspondence, cover letters, recommendation letters, thank you notes, and formal communications. The skill ensures appropriate formatting, professional language, and customization for different audiences and purposes.
Generate letters in multiple formats (PDF, DOCX, HTML) with customizable templates for different occasions and communication needs.
Purpose: Create a compelling cover letter tailored to a specific job application
Steps:
Implementation:
const { Document, Packer, Paragraph, AlignmentType, TextRun } = require('docx');
const fs = require('fs');
async function generateCoverLetter(letterData, outputPath) {
const doc = new Document({
sections: [{
properties: {
page: {
margin: {
top: 1440, // 1 inch
right: 1440,
bottom: 1440,
left: 1440
}
}
},
children: [
// Your contact information
new Paragraph({
text: letterData.sender.name,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.sender.address,
spacing: { after: 0 }
}),
new Paragraph({
text: `${letterData.sender.city}, ${letterData.sender.state} ${letterData.sender.zip}`,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.sender.email,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.sender.phone,
spacing: { after: 200 }
}),
// Date
new Paragraph({
text: new Date().toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
}),
spacing: { after: 200 }
}),
// Recipient information
new Paragraph({
text: letterData.recipient.name || 'Hiring Manager',
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.company,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.address,
spacing: { after: 0 }
}),
new Paragraph({
text: `${letterData.recipient.city}, ${letterData.recipient.state} ${letterData.recipient.zip}`,
spacing: { after: 200 }
}),
// Salutation
new Paragraph({
text: `Dear ${letterData.recipient.name || 'Hiring Manager'}:`,
spacing: { after: 200 }
}),
// Opening paragraph
new Paragraph({
text: `I am writing to express my strong interest in the ${letterData.position} position at ${letterData.recipient.company}. ${letterData.opening}`,
alignment: AlignmentType.JUSTIFIED,
spacing: { after: 200 }
}),
// Body paragraphs
...letterData.bodyParagraphs.map(para =>
new Paragraph({
text: para,
alignment: AlignmentType.JUSTIFIED,
spacing: { after: 200 }
})
),
// Closing paragraph
new Paragraph({
text: letterData.closing || `Thank you for considering my application. I am excited about the opportunity to contribute to ${letterData.recipient.company} and would welcome the chance to discuss how my skills and experience align with your needs. I look forward to hearing from you.`,
alignment: AlignmentType.JUSTIFIED,
spacing: { after: 200 }
}),
// Signature
new Paragraph({
text: 'Sincerely,',
spacing: { after: 400 }
}),
new Paragraph({
text: letterData.sender.name
})
]
}]
});
const buffer = await Packer.toBuffer(doc);
fs.writeFileSync(outputPath, buffer);
return outputPath;
}
// Helper function to generate body paragraphs based on job requirements
function generateCoverLetterBody(candidateData, jobData) {
const paragraphs = [];
// Experience paragraph
const relevantExperience = candidateData.experience
.filter(exp => exp.relevanceScore > 0.7)
.slice(0, 2);
if (relevantExperience.length > 0) {
const expText = `With ${calculateYearsExperience(candidateData.experience)} years of experience in ${jobData.industry}, I have developed strong expertise in ${jobData.keySkills.slice(0, 3).join(', ')}. In my current role at ${relevantExperience[0].company}, ${relevantExperience[0].achievements[0].toLowerCase()}`;
paragraphs.push(expText);
}
// Skills and qualifications paragraph
const matchingSkills = candidateData.skills
.filter(skill => jobData.requiredSkills.includes(skill.name))
.slice(0, 4);
if (matchingSkills.length > 0) {
const skillsText = `I am particularly well-suited for this role given my proficiency in ${matchingSkills.map(s => s.name).join(', ')}. ${candidateData.achievements.find(a => a.includes(matchingSkills[0].name)) || 'I have successfully applied these skills to deliver measurable results.'}`;
paragraphs.push(skillsText);
}
// Company-specific paragraph
if (jobData.companyInfo) {
const companyText = `I am particularly drawn to ${jobData.company} because of ${jobData.companyInfo.appeal || 'your reputation for innovation and excellence'}. I believe my background in ${jobData.relevantBackground} would enable me to make immediate contributions to your team.`;
paragraphs.push(companyText);
}
return paragraphs;
}
Purpose: Create formal business correspondence with proper formatting
Steps:
Implementation:
async function generateBusinessLetter(letterData, outputPath) {
const letterTypes = {
inquiry: {
subject: 'Inquiry Regarding',
opening: 'I am writing to inquire about',
tone: 'polite and professional'
},
complaint: {
subject: 'Concern Regarding',
opening: 'I am writing to bring to your attention',
tone: 'firm but professional'
},
proposal: {
subject: 'Proposal for',
opening: 'I am pleased to present',
tone: 'professional and enthusiastic'
},
thankyou: {
subject: 'Thank You',
opening: 'I wanted to express my sincere gratitude for',
tone: 'warm and appreciative'
}
};
const template = letterTypes[letterData.type] || letterTypes.inquiry;
const doc = new Document({
sections: [{
properties: {
page: {
margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }
}
},
children: [
// Company letterhead (if provided)
...(letterData.letterhead ? [
new Paragraph({
text: letterData.letterhead.companyName,
alignment: AlignmentType.CENTER,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.letterhead.address,
alignment: AlignmentType.CENTER,
spacing: { after: 0 }
}),
new Paragraph({
text: `${letterData.letterhead.phone} | ${letterData.letterhead.email}`,
alignment: AlignmentType.CENTER,
spacing: { after: 400 }
})
] : []),
// Date
new Paragraph({
text: new Date().toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
}),
spacing: { after: 200 }
}),
// Recipient
new Paragraph({
text: letterData.recipient.name,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.title,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.company,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.recipient.address,
spacing: { after: 200 }
}),
// Subject line
...(letterData.subject ? [
new Paragraph({
children: [
new TextRun({ text: 'RE: ', bold: true }),
new TextRun(letterData.subject)
],
spacing: { after: 200 }
})
] : []),
// Salutation
new Paragraph({
text: `Dear ${letterData.recipient.name}:`,
spacing: { after: 200 }
}),
// Body
...letterData.paragraphs.map(para =>
new Paragraph({
text: para,
alignment: AlignmentType.JUSTIFIED,
spacing: { after: 200 }
})
),
// Closing
new Paragraph({
text: letterData.closing || 'Sincerely,',
spacing: { after: 400 }
}),
// Signature
new Paragraph({
text: letterData.sender.name,
spacing: { after: 0 }
}),
new Paragraph({
text: letterData.sender.title
})
]
}]
});
const buffer = await Packer.toBuffer(doc);
fs.writeFileSync(outputPath, buffer);
return outputPath;
}
Purpose: Create letters of recommendation for employees, students, or colleagues
Steps:
Implementation:
function generateRecommendationLetter(recommendationData) {
const letterData = {
sender: recommendationData.recommender,
recipient: recommendationData.recipient || {
name: 'To Whom It May Concern'
},
type: 'recommendation',
paragraphs: [
// Opening - establish relationship
`I am writing to enthusiastically recommend ${recommendationData.candidate.name} for ${recommendationData.purpose}. I have had the pleasure of working with ${recommendationData.candidate.firstName} for ${recommendationData.duration} in my capacity as ${recommendationData.recommender.title} at ${recommendationData.recommender.company}.`,
// Qualifications and strengths
`During our time working together, ${recommendationData.candidate.firstName} has consistently demonstrated exceptional ${recommendationData.strengths.join(', ')}. ${recommendationData.standoutQualities}`,
// Specific examples
...recommendationData.examples.map(example =>
`For instance, ${example.description} This ${example.impact}`
),
// Comparison to peers (if applicable)
...(recommendationData.comparison ? [
`${recommendationData.candidate.firstName} stands out among ${recommendationData.comparison.peerGroup} for ${recommendationData.comparison.distinguishingFactors}.`
] : []),
// Strong endorsement
`I am confident that ${recommendationData.candidate.firstName} will be an outstanding ${recommendationData.targetRole} and will bring the same level of dedication, skill, and enthusiasm that I have witnessed firsthand. ${recommendationData.candidate.pronoun} has my highest recommendation without reservation.`,
// Offer additional information
`Please feel free to contact me at ${recommendationData.recommender.phone} or ${recommendationData.recommender.email} if you would like to discuss ${recommendationData.candidate.firstName}'s qualifications further.`
]
};
return generateBusinessLetter(letterData, recommendationData.outputPath);
}
Purpose: Create professional thank you letters for various occasions
Steps:
Implementation:
function generateThankYouLetter(thankYouData) {
const templates = {
interview: {
opening: `Thank you for taking the time to meet with me ${thankYouData.when} to discuss the ${thankYouData.position} position at ${thankYouData.company}.`,
body: `I enjoyed learning more about ${thankYouData.discussionTopics} and was particularly excited to hear about ${thankYouData.highlight}. Our conversation reinforced my strong interest in joining your team and contributing to ${thankYouData.contribution}.`,
closing: `I am very enthusiastic about this opportunity and believe my ${thankYouData.relevantSkills} would be a strong fit for your needs. Thank you again for your time and consideration. I look forward to hearing from you.`
},
meeting: {
opening: `Thank you for meeting with me on ${thankYouData.date} to discuss ${thankYouData.topic}.`,
body: `I found our conversation about ${thankYouData.keyPoints} very valuable. Your insights regarding ${thankYouData.insight} gave me a new perspective on ${thankYouData.subject}.`,
closing: `I appreciate your time and expertise. I look forward to our continued collaboration.`
},
gift: {
opening: `Thank you so much for the thoughtful ${thankYouData.gift}.`,
body: `Your generosity and thoughtfulness are greatly appreciated. ${thankYouData.personalNote}`,
closing: `Thank you again for thinking of me. Your kindness means a lot.`
},
networking: {
opening: `It was a pleasure meeting you at ${thankYouData.event} on ${thankYouData.date}.`,
body: `I enjoyed our conversation about ${thankYouData.topic} and found your perspective on ${thankYouData.insight} particularly interesting. I would love to stay connected and explore opportunities for ${thankYouData.futureCollaboration}.`,
closing: `Thank you for taking the time to speak with me. I've connected with you on LinkedIn and look forward to staying in touch.`
}
};
const template = templates[thankYouData.type] || templates.meeting;
return {
sender: thankYouData.sender,
recipient: thankYouData.recipient,
subject: `Thank you - ${thankYouData.regarding}`,
paragraphs: [
template.opening,
template.body,
template.closing
],
closing: 'Best regards,'
};
}
Purpose: Create multiple personalized letters from a template and data source
Steps:
Implementation:
const Handlebars = require('handlebars');
async function batchGenerateLetters(templatePath, recipientsData, outputDir) {
const template = fs.readFileSync(templatePath, 'utf8');
const compiledTemplate = Handlebars.compile(template);
const results = [];
for (const recipient of recipientsData) {
try {
// Merge recipient data with template
const letterContent = compiledTemplate(recipient);
// Generate filename
const filename = `${outputDir}/letter-${recipient.id}-${recipient.name.replace(/\s+/g, '-')}.docx`;
// Create letter data
const letterData = {
sender: recipient.sender || recipientsData.defaultSender,
recipient: {
name: recipient.name,
title: recipient.title,
company: recipient.company,
address: recipient.address
},
paragraphs: letterContent.split('\n\n').filter(p => p.trim()),
subject: recipient.subject
};
// Generate letter
await generateBusinessLetter(letterData, filename);
results.push({
success: true,
recipientId: recipient.id,
name: recipient.name,
filename: filename
});
} catch (error) {
results.push({
success: false,
recipientId: recipient.id,
name: recipient.name,
error: error.message
});
}
}
// Generate summary report
const summary = {
total: recipientsData.length,
successful: results.filter(r => r.success).length,
failed: results.filter(r => !r.success).length,
results: results
};
fs.writeFileSync(
`${outputDir}/batch-summary.json`,
JSON.stringify(summary, null, 2)
);
return summary;
}
| Action | Command/Trigger |
|---|---|
| Cover letter | "write cover letter for [position]" |
| Business letter | "create business letter to [recipient]" |
| Recommendation | "generate recommendation letter" |
| Thank you note | "write thank you letter" |
| Formal letter | "draft formal correspondence" |
| Batch letters | "create letters for [recipients]" |
Job Application Package:
{
coverLetter: generateCoverLetter(candidateData, jobData),
resume: generateResume(candidateData),
references: generateReferencesList(candidateData.references)
}
Customer Service Response:
{
type: 'response',
tone: 'apologetic and solution-oriented',
structure: ['acknowledge issue', 'explain what happened', 'describe resolution', 'offer compensation', 'prevent future']
}
Install required packages:
npm install docx
npm install handlebars # For templating
npm install pdf-lib # For PDF generation
npm install nodemailer # For email sending (optional)
Email Integration:
async function sendLetter(letterPath, recipientEmail, subject) {
const transporter = nodemailer.createTransporter(config);
await transporter.sendMail({
from: senderEmail,
to: recipientEmail,
subject: subject,
html: '<p>Please find attached letter.</p>',
attachments: [{ path: letterPath }]
});
}
Signature Integration:
async function addDigitalSignature(letterPath, signatureImagePath) {
// Add scanned signature image to letter
// Position at signature block
}
Template Library:
const letterTemplates = {
coverLetter: './templates/cover-letter.hbs',
businessInquiry: './templates/business-inquiry.hbs',
recommendation: './templates/recommendation.hbs',
thankYou: './templates/thank-you.hbs'
};
Weekly Installs
–
Repository
GitHub Stars
2
First Seen
–
Security Audits
通过 LiteLLM 代理让 Claude Code 对接 GitHub Copilot 运行 | 高级变通方案指南
31,600 周安装