mcpField
L
Letter Writer

Letter Writer

github.com/jmsktm文档处理10207 次安装40 周前更新
代码仓库

关于 Letter Writer

Letter Writer 是用于撰写商务和个人信函的技能,涵盖求职信、推荐信和感谢信等。它可按受众调整语气与格式,导出为 PDF、DOCX 或 HTML,也能基于模板和收件人数据批量生成个性化信件。

主要功能

  1. 01起草商务和个人信函
  2. 02撰写求职信、推荐信和感谢信
  3. 03根据受众调整语气与结构
  4. 04导出为 PDF、DOCX 和 HTML
  5. 05批量生成个性化信件
  6. 06使用模板合并收件人数据

适用场景

  1. 01准备求职申请信
  2. 02撰写正式商务函件
  3. 03为同事或学生撰写推荐信
  4. 04为多个收件人生成个性化信件

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jmsktm/claude-settings --skill letter-writer

安装后在 Claude Code 中输入/letter-writer确认已加载。

详细介绍

信函撰写工具

信函撰写工具可自动创建格式、语气和结构得当的商务与个人信函。它支持多种信函类型,包括商务往来信函、求职信、推荐信、感谢信和正式函件。该工具可确保格式恰当、语言专业,并根据不同受众和目的进行定制。

以多种格式(PDF、DOCX、HTML)生成信函,并提供可自定义的模板,满足不同场合和沟通需求。

核心工作流

工作流 1:生成求职信

目的: 创建一封针对特定职位申请量身定制、引人注目的求职信

步骤:

  1. 收集职位详情(职位、公司、要求)
  2. 提取候选人的相关资历
  3. 按照规范的商务格式组织信函
  4. 撰写引人入胜的开篇段落
  5. 详细介绍相关经验和成就
  6. 将技能与职位要求相联系
  7. 撰写有力的结尾,并加入行动号召
  8. 设置恰当的间距和页边距
  9. 导出为 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:商务信函生成器

目的: 创建格式规范的正式商务往来信函

步骤:

  1. 选择信函类型(询问信、投诉信、提案等)
  2. 按照商务信函结构排版
  3. 使用专业的语气和语言
  4. 根据需要添加主题行
  5. 撰写清晰、简洁的内容
  6. 添加恰当的结尾和签名栏
  7. 如有信头纸,可据此排版

实现:

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:推荐信生成器

目的: 为员工、学生或同事撰写推荐信

步骤:

  1. 收集被推荐人的相关信息
  2. 了解信函的目的和收件人
  3. 说明推荐人的资历和双方关系
  4. 详细介绍具体资历和成就
  5. 提供具体事例
  6. 适当时与同侪进行比较
  7. 给出热情洋溢的推荐
  8. 表示愿意提供更多信息

实现:

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:感谢信生成器

目的: 为各种场合撰写专业的感谢信

步骤:

  1. 确定场合(面试、礼物、会面等)
  2. 具体表达谢意
  3. 提及互动中的关键细节
  4. 巩固双方的兴趣或关系
  5. 保持简洁而真诚
  6. 使用亲切而专业的语气
  7. 根据媒介采用恰当格式

实现:

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:批量生成信函

目的: 根据模板和数据源创建多封个性化信函

步骤:

  1. 加载带占位符的信函模板
  2. 加载收件人数据(CSV、JSON、数据库)
  3. 对每位收件人:
    • 将数据与模板合并
    • 个性化内容
    • 生成信函
    • 使用唯一文件名保存
  4. 跟踪生成进度
  5. 创建摘要报告

实现:

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