[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6NTNV5YNF3SW2D8R3QYRT2J":3,"skill-same:01M6NTNV5YNF3SW2D8R3QYRT2J":69},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":47,"commitSha":48,"skillDirectory":49,"forksCount":14,"repositoryHtmlUrl":50,"repositoryHomepageUrl":6,"ownerHtmlUrl":51,"ownerBlogUrl":52,"ownerDescription":53,"updatedAt":54,"install":55,"resources":68},"01M6NTNV5YNF3SW2D8R3QYRT2J","email-infrastructure",null,"Email delivery infrastructure - DNS authentication (SPF\u002FDKIM\u002FDMARC), subdomain isolation, provider abstraction, template systems, bounce handling, warmup strategy, and deliverability monitoring.","rubicanjr\u002FFinCognis","rubicanjr","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F234912519?v=4","01M6NT156NND8J474G34SB3923","Rubi","01M6NT15B70RWXE1N3YV0BZY8A",0,"MIT","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Femail-infrastructure\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000005","邮件与沟通","SCENARIO","使用场景",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"email infrastructure","email","infrastructure","strategy","warmup","deliverability","isolation","systems","delivery","provider","subdomain","template","dmarc","dkim","spf","dns","monitoring","authentication","2026-11-10 10:12:30",false,"---\nname: email-infrastructure\ndescription: Email delivery infrastructure - DNS authentication (SPF\u002FDKIM\u002FDMARC), subdomain isolation, provider abstraction, template systems, bounce handling, warmup strategy, and deliverability monitoring.\n---\n\n# Email Infrastructure\n\nProduction email delivery requires DNS authentication, domain isolation, and provider-agnostic architecture. A single misconfiguration can land your entire domain in spam.\n\n## GOOD vs BAD: Domain Strategy\n\n```\nBAD:  Send bulk marketing from example.com\n      → Spam complaints tank your main domain reputation\n      → Transactional emails (password reset, receipts) start landing in spam\n      → Recovery takes weeks of warmup\n\nGOOD: Subdomain isolation with separate reputations\n      → mail.example.com        for transactional (password reset, receipts, 2FA)\n      → notify.example.com      for product notifications (comments, mentions)\n      → marketing.example.com   for bulk campaigns (newsletters, promotions)\n      → Each subdomain has independent reputation — one bad campaign does not poison the rest\n```\n\n## DNS Authentication: SPF + DKIM + DMARC\n\n```\n# SPF — declare which servers can send from your domain\nmail.example.com     TXT  \"v=spf1 include:_spf.provider.com ~all\"\n\n# DKIM — cryptographic signature on every email\nselector._domainkey.mail.example.com  TXT  \"v=DKIM1; k=rsa; p=MIGf...\"\n\n# DMARC — policy for failed authentication (progressive rollout)\n# Week 1-2: monitor only\n_dmarc.mail.example.com  TXT  \"v=DMARC1; p=none; rua=mailto:dmarc@example.com\"\n\n# Week 3-4: quarantine suspicious emails\n_dmarc.mail.example.com  TXT  \"v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc@example.com\"\n\n# Week 5+: reject after confidence builds\n_dmarc.mail.example.com  TXT  \"v=DMARC1; p=reject; rua=mailto:dmarc@example.com\"\n```\n\nNever jump straight to `p=reject`. The progressive rollout catches misconfigurations before they block legitimate mail.\n\n## Email Provider Abstraction\n\n```typescript\n\u002F\u002F Swap Resend, SES, Postmark, or Mailgun without touching business logic\n\ninterface EmailProvider {\n  send(message: EmailMessage): Promise\u003CEmailResult>\n  sendBatch(messages: EmailMessage[]): Promise\u003CEmailResult[]>\n}\n\ninterface EmailMessage {\n  from: string\n  to: string | string[]\n  subject: string\n  html: string\n  text?: string\n  replyTo?: string\n  headers?: Record\u003Cstring, string>\n  tags?: Record\u003Cstring, string>\n}\n\ninterface EmailResult {\n  id: string\n  status: 'sent' | 'queued' | 'failed'\n  error?: string\n}\n\n\u002F\u002F Factory selects provider from config — no hardcoded vendor\nfunction createEmailProvider(config: { provider: string }): EmailProvider {\n  switch (config.provider) {\n    case 'resend':    return new ResendProvider()\n    case 'ses':       return new SESProvider()\n    case 'postmark':  return new PostmarkProvider()\n    default:          throw new Error(`Unknown email provider: ${config.provider}`)\n  }\n}\n```\n\n## Transactional vs Marketing Separation\n\n```typescript\ninterface EmailService {\n  sendTransactional(message: EmailMessage): Promise\u003CEmailResult>\n  sendMarketing(message: EmailMessage): Promise\u003CEmailResult>\n}\n\nclass ProductionEmailService implements EmailService {\n  constructor(\n    private transactional: EmailProvider,  \u002F\u002F high-deliverability provider\n    private marketing: EmailProvider       \u002F\u002F bulk-optimized provider\n  ) {}\n\n  async sendTransactional(message: EmailMessage): Promise\u003CEmailResult> {\n    \u002F\u002F Transactional: password reset, receipts, 2FA — must arrive instantly\n    \u002F\u002F Use mail.example.com subdomain, high-priority provider\n    return this.transactional.send({\n      ...message,\n      from: `noreply@mail.example.com`,\n      headers: { 'X-Priority': '1' }\n    })\n  }\n\n  async sendMarketing(message: EmailMessage): Promise\u003CEmailResult> {\n    \u002F\u002F Marketing: newsletters, promotions — rate-limited, includes unsubscribe\n    \u002F\u002F Use marketing.example.com subdomain, bulk provider\n    return this.marketing.send({\n      ...message,\n      from: `hello@marketing.example.com`,\n      headers: { 'List-Unsubscribe': `\u003Chttps:\u002F\u002Fexample.com\u002Funsubscribe>` }\n    })\n  }\n}\n```\n\n## Template System (MJML)\n\n```typescript\n\u002F\u002F MJML compiles to responsive HTML that works across all email clients\n\u002F\u002F Compile at build time, not runtime\n\nimport mjml2html from 'mjml'\n\nconst mjmlTemplate = `\n\u003Cmjml>\n  \u003Cmj-head>\n    \u003Cmj-attributes>\n      \u003Cmj-all font-family=\"system-ui, -apple-system, sans-serif\" \u002F>\n      \u003Cmj-text font-size=\"16px\" line-height=\"1.5\" color=\"#1a1a1a\" \u002F>\n    \u003C\u002Fmj-attributes>\n    \u003Cmj-style>\n      @media (prefers-color-scheme: dark) {\n        .dark-bg { background-color: #1a1a1a !important; }\n        .dark-text { color: #e5e5e5 !important; }\n      }\n    \u003C\u002Fmj-style>\n  \u003C\u002Fmj-head>\n  \u003Cmj-body>\n    \u003Cmj-section css-class=\"dark-bg\">\n      \u003Cmj-column>\n        \u003Cmj-text css-class=\"dark-text\">Hello {{name}},\u003C\u002Fmj-text>\n        \u003Cmj-text css-class=\"dark-text\">{{body}}\u003C\u002Fmj-text>\n        \u003Cmj-button href=\"{{actionUrl}}\" background-color=\"#2563eb\">\n          {{actionLabel}}\n        \u003C\u002Fmj-button>\n      \u003C\u002Fmj-column>\n    \u003C\u002Fmj-section>\n  \u003C\u002Fmj-body>\n\u003C\u002Fmjml>\n`\n\nfunction escapeHtml(str: string): string {\n  return str.replace(\u002F&\u002Fg, '&amp;').replace(\u002F\u003C\u002Fg, '&lt;').replace(\u002F>\u002Fg, '&gt;').replace(\u002F\"\u002Fg, '&quot;')\n}\n\nfunction compileTemplate(mjml: string, vars: Record\u003Cstring, string>): string {\n  let compiled = mjml\n  for (const [key, value] of Object.entries(vars)) {\n    compiled = compiled.replaceAll(`{{${key}}}`, escapeHtml(value))\n  }\n  const { html, errors } = mjml2html(compiled)\n  if (errors.length > 0) {\n    throw new Error(`MJML compilation errors: ${errors.map(e => e.message).join(', ')}`)\n  }\n  return html\n}\n```\n\n## Bounce and Complaint Handling\n\n```typescript\n\u002F\u002F Webhook handler for provider callbacks (bounces, complaints, deliveries)\n\ninterface BounceEvent {\n  type: 'bounce' | 'complaint' | 'delivery'\n  email: string\n  reason?: string\n  timestamp: string\n}\n\nasync function handleEmailWebhook(event: BounceEvent): Promise\u003Cvoid> {\n  switch (event.type) {\n    case 'bounce':\n      \u002F\u002F Hard bounce: address does not exist — never send again\n      await db.emailSuppression.upsert({\n        where: { email: event.email },\n        create: { email: event.email, reason: 'hard_bounce', suppressedAt: new Date() },\n        update: { reason: 'hard_bounce', suppressedAt: new Date() }\n      })\n      break\n\n    case 'complaint':\n      \u002F\u002F Spam complaint: user marked as spam — suppress immediately\n      await db.emailSuppression.upsert({\n        where: { email: event.email },\n        create: { email: event.email, reason: 'complaint', suppressedAt: new Date() },\n        update: { reason: 'complaint', suppressedAt: new Date() }\n      })\n      \u002F\u002F Alert if complaint rate exceeds 0.1% (ISP threshold)\n      await checkComplaintRate()\n      break\n\n    case 'delivery':\n      await db.emailLog.update({\n        where: { email: event.email },\n        data: { deliveredAt: new Date() }\n      })\n      break\n  }\n}\n\n\u002F\u002F Always check suppression list before sending\nasync function isSuppressed(email: string): Promise\u003Cboolean> {\n  const entry = await db.emailSuppression.findUnique({ where: { email } })\n  return entry !== null\n}\n```\n\n## Domain Warmup Strategy\n\n```\nNew domain\u002FIP starts with zero reputation. Send too fast and ISPs block you.\n\nWeek 1:     50 emails\u002Fday   → Send to your most engaged users only\nWeek 2:    200 emails\u002Fday   → Expand to users who opened in last 30 days\nWeek 3:    500 emails\u002Fday   → Include 90-day active users\nWeek 4:  1,000 emails\u002Fday   → General audience, monitor bounce rate\nWeek 5:  5,000 emails\u002Fday   → Scale up if bounce \u003C 2% and complaints \u003C 0.1%\nWeek 6: 10,000 emails\u002Fday   → Full volume if metrics stay clean\nWeek 8+: Full send           → Maintain list hygiene going forward\n\nCRITICAL THRESHOLDS:\n  Bounce rate  > 5%   → STOP sending, clean your list\n  Complaint rate > 0.1% → STOP sending, review content and targeting\n  Open rate    \u003C 10%  → Re-evaluate subject lines and audience\n```\n\n## Deliverability Monitoring\n\n```typescript\ninterface DeliverabilityMetrics {\n  sent: number\n  delivered: number\n  bounced: number\n  complained: number\n  opened: number\n  clicked: number\n}\n\nasync function getDailyMetrics(date: string): Promise\u003CDeliverabilityMetrics> {\n  const metrics = await db.emailLog.aggregate({\n    where: { sentAt: { gte: new Date(date), lt: new Date(date + 'T23:59:59Z') } },\n    _count: { id: true },\n    \u002F\u002F Group by status for each metric\n  })\n  return metrics\n}\n\nasync function checkHealthThresholds(metrics: DeliverabilityMetrics): Promise\u003Cvoid> {\n  if (metrics.sent === 0) return\n\n  const bounceRate = metrics.bounced \u002F metrics.sent\n  const complaintRate = metrics.complained \u002F metrics.sent\n  const deliveryRate = metrics.delivered \u002F metrics.sent\n\n  if (bounceRate > 0.05) {\n    await alertOps('Bounce rate critical', `${(bounceRate * 100).toFixed(1)}% — pause sending`)\n  }\n  if (complaintRate > 0.001) {\n    await alertOps('Complaint rate critical', `${(complaintRate * 100).toFixed(2)}% — review content`)\n  }\n  if (deliveryRate \u003C 0.95) {\n    await alertOps('Delivery rate low', `${(deliveryRate * 100).toFixed(1)}% — check DNS and reputation`)\n  }\n}\n```\n\n## Pre-Send Checklist\n\n```\nBefore every send, verify:\n  1. Recipient is not on suppression list (bounces + complaints)\n  2. SPF\u002FDKIM\u002FDMARC records are valid for the sending subdomain\n  3. Unsubscribe link is present (CAN-SPAM, GDPR requirement)\n  4. Plain text version exists alongside HTML\n  5. From address matches the authenticated subdomain\n  6. List-Unsubscribe header is set for bulk sends\n  7. Subject line is not empty and under 78 characters\n```\n\n**Key principle**: Treat email infrastructure like a reputation system. Subdomain isolation protects your core domain. Progressive DMARC rollout catches issues before they block mail. Always check the suppression list before sending. Monitor bounce and complaint rates daily — by the time you notice spam folder placement, the damage is already done.\n","# Email Infrastructure\n\nProduction email delivery requires DNS authentication, domain isolation, and provider-agnostic architecture. A single misconfiguration can land your entire domain in spam.\n\n## GOOD vs BAD: Domain Strategy\n\n```\nBAD:  Send bulk marketing from example.com\n      → Spam complaints tank your main domain reputation\n      → Transactional emails (password reset, receipts) start landing in spam\n      → Recovery takes weeks of warmup\n\nGOOD: Subdomain isolation with separate reputations\n      → mail.example.com        for transactional (password reset, receipts, 2FA)\n      → notify.example.com      for product notifications (comments, mentions)\n      → marketing.example.com   for bulk campaigns (newsletters, promotions)\n      → Each subdomain has independent reputation — one bad campaign does not poison the rest\n```\n\n## DNS Authentication: SPF + DKIM + DMARC\n\n```\n# SPF — declare which servers can send from your domain\nmail.example.com     TXT  \"v=spf1 include:_spf.provider.com ~all\"\n\n# DKIM — cryptographic signature on every email\nselector._domainkey.mail.example.com  TXT  \"v=DKIM1; k=rsa; p=MIGf...\"\n\n# DMARC — policy for failed authentication (progressive rollout)\n# Week 1-2: monitor only\n_dmarc.mail.example.com  TXT  \"v=DMARC1; p=none; rua=mailto:dmarc@example.com\"\n\n# Week 3-4: quarantine suspicious emails\n_dmarc.mail.example.com  TXT  \"v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc@example.com\"\n\n# Week 5+: reject after confidence builds\n_dmarc.mail.example.com  TXT  \"v=DMARC1; p=reject; rua=mailto:dmarc@example.com\"\n```\n\nNever jump straight to `p=reject`. The progressive rollout catches misconfigurations before they block legitimate mail.\n\n## Email Provider Abstraction\n\n```typescript\n\u002F\u002F Swap Resend, SES, Postmark, or Mailgun without touching business logic\n\ninterface EmailProvider {\n  send(message: EmailMessage): Promise\u003CEmailResult>\n  sendBatch(messages: EmailMessage[]): Promise\u003CEmailResult[]>\n}\n\ninterface EmailMessage {\n  from: string\n  to: string | string[]\n  subject: string\n  html: string\n  text?: string\n  replyTo?: string\n  headers?: Record\u003Cstring, string>\n  tags?: Record\u003Cstring, string>\n}\n\ninterface EmailResult {\n  id: string\n  status: 'sent' | 'queued' | 'failed'\n  error?: string\n}\n\n\u002F\u002F Factory selects provider from config — no hardcoded vendor\nfunction createEmailProvider(config: { provider: string }): EmailProvider {\n  switch (config.provider) {\n    case 'resend':    return new ResendProvider()\n    case 'ses':       return new SESProvider()\n    case 'postmark':  return new PostmarkProvider()\n    default:          throw new Error(`Unknown email provider: ${config.provider}`)\n  }\n}\n```\n\n## Transactional vs Marketing Separation\n\n```typescript\ninterface EmailService {\n  sendTransactional(message: EmailMessage): Promise\u003CEmailResult>\n  sendMarketing(message: EmailMessage): Promise\u003CEmailResult>\n}\n\nclass ProductionEmailService implements EmailService {\n  constructor(\n    private transactional: EmailProvider,  \u002F\u002F high-deliverability provider\n    private marketing: EmailProvider       \u002F\u002F bulk-optimized provider\n  ) {}\n\n  async sendTransactional(message: EmailMessage): Promise\u003CEmailResult> {\n    \u002F\u002F Transactional: password reset, receipts, 2FA — must arrive instantly\n    \u002F\u002F Use mail.example.com subdomain, high-priority provider\n    return this.transactional.send({\n      ...message,\n      from: `noreply@mail.example.com`,\n      headers: { 'X-Priority': '1' }\n    })\n  }\n\n  async sendMarketing(message: EmailMessage): Promise\u003CEmailResult> {\n    \u002F\u002F Marketing: newsletters, promotions — rate-limited, includes unsubscribe\n    \u002F\u002F Use marketing.example.com subdomain, bulk provider\n    return this.marketing.send({\n      ...message,\n      from: `hello@marketing.example.com`,\n      headers: { 'List-Unsubscribe': `\u003Chttps:\u002F\u002Fexample.com\u002Funsubscribe>` }\n    })\n  }\n}\n```\n\n## Template System (MJML)\n\n```typescript\n\u002F\u002F MJML compiles to responsive HTML that works across all email clients\n\u002F\u002F Compile at build time, not runtime\n\nimport mjml2html from 'mjml'\n\nconst mjmlTemplate = `\n\u003Cmjml>\n  \u003Cmj-head>\n    \u003Cmj-attributes>\n      \u003Cmj-all font-family=\"system-ui, -apple-system, sans-serif\" \u002F>\n      \u003Cmj-text font-size=\"16px\" line-height=\"1.5\" color=\"#1a1a1a\" \u002F>\n    \u003C\u002Fmj-attributes>\n    \u003Cmj-style>\n      @media (prefers-color-scheme: dark) {\n        .dark-bg { background-color: #1a1a1a !important; }\n        .dark-text { color: #e5e5e5 !important; }\n      }\n    \u003C\u002Fmj-style>\n  \u003C\u002Fmj-head>\n  \u003Cmj-body>\n    \u003Cmj-section css-class=\"dark-bg\">\n      \u003Cmj-column>\n        \u003Cmj-text css-class=\"dark-text\">Hello {{name}},\u003C\u002Fmj-text>\n        \u003Cmj-text css-class=\"dark-text\">{{body}}\u003C\u002Fmj-text>\n        \u003Cmj-button href=\"{{actionUrl}}\" background-color=\"#2563eb\">\n          {{actionLabel}}\n        \u003C\u002Fmj-button>\n      \u003C\u002Fmj-column>\n    \u003C\u002Fmj-section>\n  \u003C\u002Fmj-body>\n\u003C\u002Fmjml>\n`\n\nfunction escapeHtml(str: string): string {\n  return str.replace(\u002F&\u002Fg, '&amp;').replace(\u002F\u003C\u002Fg, '&lt;').replace(\u002F>\u002Fg, '&gt;').replace(\u002F\"\u002Fg, '&quot;')\n}\n\nfunction compileTemplate(mjml: string, vars: Record\u003Cstring, string>): string {\n  let compiled = mjml\n  for (const [key, value] of Object.entries(vars)) {\n    compiled = compiled.replaceAll(`{{${key}}}`, escapeHtml(value))\n  }\n  const { html, errors } = mjml2html(compiled)\n  if (errors.length > 0) {\n    throw new Error(`MJML compilation errors: ${errors.map(e => e.message).join(', ')}`)\n  }\n  return html\n}\n```\n\n## Bounce and Complaint Handling\n\n```typescript\n\u002F\u002F Webhook handler for provider callbacks (bounces, complaints, deliveries)\n\ninterface BounceEvent {\n  type: 'bounce' | 'complaint' | 'delivery'\n  email: string\n  reason?: string\n  timestamp: string\n}\n\nasync function handleEmailWebhook(event: BounceEvent): Promise\u003Cvoid> {\n  switch (event.type) {\n    case 'bounce':\n      \u002F\u002F Hard bounce: address does not exist — never send again\n      await db.emailSuppression.upsert({\n        where: { email: event.email },\n        create: { email: event.email, reason: 'hard_bounce', suppressedAt: new Date() },\n        update: { reason: 'hard_bounce', suppressedAt: new Date() }\n      })\n      break\n\n    case 'complaint':\n      \u002F\u002F Spam complaint: user marked as spam — suppress immediately\n      await db.emailSuppression.upsert({\n        where: { email: event.email },\n        create: { email: event.email, reason: 'complaint', suppressedAt: new Date() },\n        update: { reason: 'complaint', suppressedAt: new Date() }\n      })\n      \u002F\u002F Alert if complaint rate exceeds 0.1% (ISP threshold)\n      await checkComplaintRate()\n      break\n\n    case 'delivery':\n      await db.emailLog.update({\n        where: { email: event.email },\n        data: { deliveredAt: new Date() }\n      })\n      break\n  }\n}\n\n\u002F\u002F Always check suppression list before sending\nasync function isSuppressed(email: string): Promise\u003Cboolean> {\n  const entry = await db.emailSuppression.findUnique({ where: { email } })\n  return entry !== null\n}\n```\n\n## Domain Warmup Strategy\n\n```\nNew domain\u002FIP starts with zero reputation. Send too fast and ISPs block you.\n\nWeek 1:     50 emails\u002Fday   → Send to your most engaged users only\nWeek 2:    200 emails\u002Fday   → Expand to users who opened in last 30 days\nWeek 3:    500 emails\u002Fday   → Include 90-day active users\nWeek 4:  1,000 emails\u002Fday   → General audience, monitor bounce rate\nWeek 5:  5,000 emails\u002Fday   → Scale up if bounce \u003C 2% and complaints \u003C 0.1%\nWeek 6: 10,000 emails\u002Fday   → Full volume if metrics stay clean\nWeek 8+: Full send           → Maintain list hygiene going forward\n\nCRITICAL THRESHOLDS:\n  Bounce rate  > 5%   → STOP sending, clean your list\n  Complaint rate > 0.1% → STOP sending, review content and targeting\n  Open rate    \u003C 10%  → Re-evaluate subject lines and audience\n```\n\n## Deliverability Monitoring\n\n```typescript\ninterface DeliverabilityMetrics {\n  sent: number\n  delivered: number\n  bounced: number\n  complained: number\n  opened: number\n  clicked: number\n}\n\nasync function getDailyMetrics(date: string): Promise\u003CDeliverabilityMetrics> {\n  const metrics = await db.emailLog.aggregate({\n    where: { sentAt: { gte: new Date(date), lt: new Date(date + 'T23:59:59Z') } },\n    _count: { id: true },\n    \u002F\u002F Group by status for each metric\n  })\n  return metrics\n}\n\nasync function checkHealthThresholds(metrics: DeliverabilityMetrics): Promise\u003Cvoid> {\n  if (metrics.sent === 0) return\n\n  const bounceRate = metrics.bounced \u002F metrics.sent\n  const complaintRate = metrics.complained \u002F metrics.sent\n  const deliveryRate = metrics.delivered \u002F metrics.sent\n\n  if (bounceRate > 0.05) {\n    await alertOps('Bounce rate critical', `${(bounceRate * 100).toFixed(1)}% — pause sending`)\n  }\n  if (complaintRate > 0.001) {\n    await alertOps('Complaint rate critical', `${(complaintRate * 100).toFixed(2)}% — review content`)\n  }\n  if (deliveryRate \u003C 0.95) {\n    await alertOps('Delivery rate low', `${(deliveryRate * 100).toFixed(1)}% — check DNS and reputation`)\n  }\n}\n```\n\n## Pre-Send Checklist\n\n```\nBefore every send, verify:\n  1. Recipient is not on suppression list (bounces + complaints)\n  2. SPF\u002FDKIM\u002FDMARC records are valid for the sending subdomain\n  3. Unsubscribe link is present (CAN-SPAM, GDPR requirement)\n  4. Plain text version exists alongside HTML\n  5. From address matches the authenticated subdomain\n  6. List-Unsubscribe header is set for bulk sends\n  7. Subject line is not empty and under 78 characters\n```\n\n**Key principle**: Treat email infrastructure like a reputation system. Subdomain isolation protects your core domain. Progressive DMARC rollout catches issues before they block mail. Always check the suppression list before sending. Monitor bounce and complaint rates daily — by the time you notice spam folder placement, the damage is already done.\n",{"name":5,"description":7},"main","70e1c350500ee750987420bbae48837afa906b7e","skills\u002Femail-infrastructure","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis","https:\u002F\u002Fgithub.com\u002Frubicanjr","linktr.ee\u002Ffinanskodu","Industrial Engineer & CIO @FinansKodu. Architecting AI-driven financial agents and autonomous workflows. 🏗️ Building systems, not just prompts.","2026-06-09 13:50:15",{"source":8,"skillName":5,"commands":56,"prompt":66,"zipAvailable":67},[57,60,63],{"tool":58,"command":59},"npx","npx skills add rubicanjr\u002FFinCognis --skill email-infrastructure",{"tool":61,"command":62},"bunx","bunx skills add rubicanjr\u002FFinCognis --skill email-infrastructure",{"tool":64,"command":65},"pnpm","pnpm dlx skills add rubicanjr\u002FFinCognis --skill email-infrastructure","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Femail-infrastructure\u002FSKILL.md",true,[],[70,89,98,118,148,167],{"skillNo":71,"name":72,"nameZh":6,"description":73,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":79,"publishedAt":42},"01M6NWS9DAXJTADT4T5MB49X8W","workflow-router","Goal-based workflow orchestration - routes tasks to specialist agents based on user goals","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fworkflow-router\u002FSKILL.md",[76],{"categoryNo":77,"categoryName":78,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[80,81,82,83,84,85,86,87,88],"workflow router","workflow","router","orchestration","goals","goal","user","workflow orchestration","tasks",{"skillNo":90,"name":91,"nameZh":6,"description":92,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":42},"01M6NWS3RETSC0SHP16HP66E14","wiring","Wiring Verification","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fwiring\u002FSKILL.md",[],[91,96,97],"verification","false",{"skillNo":99,"name":100,"nameZh":6,"description":101,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":107,"publishedAt":42},"01M6NWS0XW9CVQZBDA1EGW0TWC","websocket-patterns","Connection management, room patterns, reconnection strategies, message buffering, and binary protocol design.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fwebsocket-patterns\u002Fskill.md",[104],{"categoryNo":105,"categoryName":106,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",[108,109,110,111,112,113,114,115,116,117],"websocket","patterns","websocket patterns","design","protocol","management","message","strategies","binary","connection",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":128,"publishedAt":42},"01M6NWRDQDX9ZNETAWRRMQWV52","visual-verdict","Screenshot comparison QA for frontend development. Takes a screenshot of the current implementation, scores it across multiple visual dimensions, and returns a structured PASS\u002FREVISE\u002FFAIL verdict with concrete fixes. Use when implementing UI from a design reference or verifying visual correctness.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fvisual-verdict\u002FSKILL.md",[124,127],{"categoryNo":125,"categoryName":126,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":77,"categoryName":78,"taxonomyType":21,"taxonomyTypeDesc":22},[129,130,131,132,133,134,135,136,137,138,139,140,141,111,142,143,144,145,146,147],"visual","verdict","visual verdict","ui","across","revise","comparison","correctness","implementing","for","fixes","dimensions","frontend","development","qa","screenshot","returns","use","frontend development",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":154,"publishedAt":42},"01M6NWR8HSNRS7MNDK2J02QYMN","verification-loop","Comprehensive verification system covering build, types, lint, tests, security, and diff review before a PR.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fverification-loop\u002FSKILL.md",[],[155,156,96,157,158,159,160,161,162,163,164,165,166],"verification loop","loop","lint","review","security","pr","system","diff","build","tests","diff review","types",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":173,"publishedAt":42},"01M6NWR4HHSFR0VR5EXFRWA747","vector-db-patterns","Embedding strategies, ANN algorithms, hybrid search, RAG chunking strategies, and reranking for semantic search and retrieval.","https:\u002F\u002Fgithub.com\u002Frubicanjr\u002FFinCognis\u002Fblob\u002Fmain\u002Fskills\u002Fvector-db-patterns\u002Fskill.md",[],[174,175,176,177,109,178,179,180,181,115,182,183,184,185,186,138,187,188],"vector db patterns","vector db","db","vector","semantic search","search","embedding strategies","algorithms","chunking","semantic","retrieval","embedding","Hybrid Search","hybrid","rag"]