关于 Letter Writer
Letter Writer 是用于撰写商务和个人信函的技能,涵盖求职信、推荐信和感谢信等。它可按受众调整语气与格式,导出为 PDF、DOCX 或 HTML,也能基于模板和收件人数据批量生成个性化信件。
主要功能
- 01起草商务和个人信函
- 02撰写求职信、推荐信和感谢信
- 03根据受众调整语气与结构
- 04导出为 PDF、DOCX 和 HTML
- 05批量生成个性化信件
- 06使用模板合并收件人数据
适用场景
- 01准备求职申请信
- 02撰写正式商务函件
- 03为同事或学生撰写推荐信
- 04为多个收件人生成个性化信件
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jmsktm/ claude-settings --skill letter-writer安装后在 Claude Code 中输入/letter-writer确认已加载。
详细介绍
信函撰写工具
信函撰写工具可自动创建格式、语气和结构得当的商务与个人信函。它支持多种信函类型,包括商务往来信函、求职信、推荐信、感谢信和正式函件。该工具可确保格式恰当、语言专业,并根据不同受众和目的进行定制。
以多种格式(PDF、DOCX、HTML)生成信函,并提供可自定义的模板,满足不同场合和沟通需求。
核心工作流
工作流 1:生成求职信
目的: 创建一封针对特定职位申请量身定制、引人注目的求职信
步骤:
- 收集职位详情(职位、公司、要求)
- 提取候选人的相关资历
- 按照规范的商务格式组织信函
- 撰写引人入胜的开篇段落
- 详细介绍相关经验和成就
- 将技能与职位要求相联系
- 撰写有力的结尾,并加入行动号召
- 设置恰当的间距和页边距
- 导出为 PDF 和 DOCX
实现:
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;
}
工作流 2:商务信函生成器
目的: 创建格式规范的正式商务往来信函
步骤:
- 选择信函类型(询问信、投诉信、提案等)
- 按照商务信函结构排版
- 使用专业的语气和语言
- 根据需要添加主题行
- 撰写清晰、简洁的内容
- 添加恰当的结尾和签名栏
- 如有信头纸,可据此排版
实现:
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;
}
工作流 3:推荐信生成器
目的: 为员工、学生或同事撰写推荐信
步骤:
- 收集被推荐人的相关信息
- 了解信函的目的和收件人
- 说明推荐人的资历和双方关系
- 详细介绍具体资历和成就
- 提供具体事例
- 适当时与同侪进行比较
- 给出热情洋溢的推荐
- 表示愿意提供更多信息
实现:
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);
}
工作流 4:感谢信生成器
目的: 为各种场合撰写专业的感谢信
步骤:
- 确定场合(面试、礼物、会面等)
- 具体表达谢意
- 提及互动中的关键细节
- 巩固双方的兴趣或关系
- 保持简洁而真诚
- 使用亲切而专业的语气
- 根据媒介采用恰当格式
实现:
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,'
};
}
工作流 5:批量生成信函
目的: 根据模板和数据源创建多封个性化信函
步骤:
- 加载带占位符的信函模板
- 加载收件人数据(CSV、JSON、数据库)
- 对每位收件人:
- 将数据与模板合并
- 个性化内容
- 生成信函
- 使用唯一文件名保存
- 跟踪生成进度
- 创建摘要报告
实现:
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;
}
快速参考
| 操作 | 命令/触发语 |
|---|---|
| 求职信 | "为 [position] 撰写求职信" |
| 商务信函 | "给 [recipient] 写一封商务信函" |
| 推荐信 | "生成推荐信" |
| 感谢信 | "写一封感谢信" |
| 正式信函 | "起草正式函件" |
| 批量信函 | "为 [recipients] 创建信函" |
最佳实践
- 格式规范: 使用标准商务信函格式,并确保间距正确
- 专业语气: 根据目的和受众调整语气
- 简洁明了: 表达清晰直接,避免不必要的词语
- 仔细校对: 确保没有拼写或语法错误
- 个性化: 为每封信定制内容;避免使用通用内容
- 具体细节: 提供具体示例和详细信息
- 主动语态: 使用主动语态,让表达更有力、更清晰
- 长度适当: 求职信:3-4 个段落;商务信函:按需撰写,但保持简洁
- 行动号召: 以明确的后续步骤或预期结果收尾
- 签名: 添加规范的签名栏,并附上联系信息
- 格式设置: 统一字体、页边距和间距
- 及时发送: 在 24-48 小时内发送感谢信
常见模式
求职申请材料包:
{
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'
};
评论
支持 Markdown