npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rindrics/slackmail

v0.1.5

Published

Turn Slack into your email client - receive and send emails directly from Slack

Downloads

393

Readme

@rindrics/slackmail

npm version License: MIT

Turn Slack into your email client - receive and send emails directly from Slack.

Features

  • 📬 Receive emails in Slack channels
  • 📧 Parse raw email content (RFC 5322)
  • 🔄 Built-in retry with exponential backoff
  • 🏗️ Clean architecture with pluggable storage

Coming Soon: Send emails directly from Slack

Installation

npm install @rindrics/slackmail
# or
pnpm add @rindrics/slackmail
# or
yarn add @rindrics/slackmail

Quick Start

import {
  createSlackApp,
  createEmailReceivedHandler,
  ReceiveMailUseCase,
  SimpleEmailParser,
} from '@rindrics/slackmail';

// 1. Create Slack app
const { app } = createSlackApp({
  signingSecret: process.env.SLACK_SIGNING_SECRET!,
  botToken: process.env.SLACK_BOT_TOKEN!,
  channel: process.env.SLACK_CHANNEL_ID!,
});

// 2. Create email handler
const onEmailReceived = createEmailReceivedHandler(
  app,
  process.env.SLACK_CHANNEL_ID!,
);

// 3. Create use case with your storage implementation
const useCase = new ReceiveMailUseCase({
  storageRepository: yourStorageRepository, // Implement StorageRepository interface
  emailParser: new SimpleEmailParser(),
  onEmailReceived,
});

// 4. Process email
await useCase.execute({ storageKey: 'path/to/email' });

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    @rindrics/slackmail                          │
├─────────────────────────────────────────────────────────────────┤
│  Domain Layer                                                   │
│  ├── Email entity                                               │
│  ├── EmailParser interface                                      │
│  └── StorageRepository interface                                │
├─────────────────────────────────────────────────────────────────┤
│  Application Layer                                              │
│  └── ReceiveMailUseCase                                         │
├─────────────────────────────────────────────────────────────────┤
│  Presentation Layer                                             │
│  ├── Slack App (Bolt)                                           │
│  └── Email Formatter                                            │
└─────────────────────────────────────────────────────────────────┘

API Reference

createSlackApp(config)

Create a Slack Bolt app configured for AWS Lambda.

const { app, receiver } = createSlackApp({
  signingSecret: string,  // Slack signing secret
  botToken: string,       // Bot user OAuth token (xoxb-...)
  channel: string,        // Default channel ID
});

createEmailReceivedHandler(app, channel, config?)

Create a callback for handling received emails.

const handler = createEmailReceivedHandler(app, channel, {
  maxRetries: 2,           // Default: 2
  initialBackoffMs: 1000,  // Default: 1000
  onFailure: async (record) => {
    // Handle permanently failed emails
  },
});

ReceiveMailUseCase

Main use case for processing emails.

const useCase = new ReceiveMailUseCase({
  storageRepository: StorageRepository,
  emailParser: EmailParser,
  onEmailReceived: (email: Email) => Promise<void>,
});

const result = await useCase.execute({ storageKey: 'path/to/email' });
// result.email contains the parsed Email object

SimpleEmailParser

Built-in email parser for basic RFC 5322 emails.

const parser = new SimpleEmailParser();
const email = await parser.parse(rawEmailContent);

Note: For production use with complex MIME multipart emails, consider using mailparser and implementing the EmailParser interface.

Interfaces

StorageRepository

interface StorageRepository {
  fetchRawEmail(key: string): Promise<string>;
}

EmailParser

interface EmailParser {
  parse(raw: string | Buffer): Promise<Email>;
}

Email

interface Email {
  messageId: string;
  from: EmailAddress;
  to: EmailAddress[];
  cc?: EmailAddress[];
  subject: string;
  body: {
    text?: string;
    html?: string;
  };
  date: Date;
  inReplyTo?: string;
  references?: string[];
}

interface EmailAddress {
  name?: string;
  address: string;
}

Deploy to AWS (Quick Start)

Want a complete, production-ready setup with AWS infrastructure (SES, S3, Lambda)?

👉 Fork the Rindrics/slackmail repository

The repository includes:

  • 🏗️ Pulumi IaC - S3, Lambda, SES, Route53, IAM
  • 🔄 GitHub Actions - CI/CD with OIDC authentication
  • 📧 SES Email Receiving - Receive emails at your custom domain
  • 📦 Ready to deploy - Just configure your secrets and deploy
git clone https://github.com/Rindrics/slackmail.git
cd slackmail
pnpm install
# Configure your AWS and Slack credentials, then:
cd infra/aws && pnpm run up

See the repository README for detailed setup instructions.

Slack App Setup

  1. Create a new app at Slack API
  2. Add the following Bot Token Scopes:
    • chat:write - Post messages
    • chat:write.public - Post to public channels without joining
  3. Install the app to your workspace
  4. Note your credentials:
    • Bot User OAuth TokenSLACK_BOT_TOKEN
    • Signing SecretSLACK_SIGNING_SECRET

Examples

AWS Lambda with S3

import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import type { S3Handler } from 'aws-lambda';
import {
  createSlackApp,
  createEmailReceivedHandler,
  ReceiveMailUseCase,
  SimpleEmailParser,
  type StorageRepository,
} from '@rindrics/slackmail';

// Implement StorageRepository for S3
class S3StorageRepository implements StorageRepository {
  constructor(
    private bucket: string,
    private client = new S3Client({}),
  ) {}

  async fetchRawEmail(key: string): Promise<string> {
    const response = await this.client.send(
      new GetObjectCommand({ Bucket: this.bucket, Key: key }),
    );
    return response.Body!.transformToString();
  }
}

// Lambda handler
export const handler: S3Handler = async (event) => {
  const { app } = createSlackApp({
    signingSecret: process.env.SLACK_SIGNING_SECRET!,
    botToken: process.env.SLACK_BOT_TOKEN!,
    channel: process.env.SLACK_CHANNEL_ID!,
  });

  for (const record of event.Records) {
    const bucket = record.s3.bucket.name;
    const key = decodeURIComponent(record.s3.object.key.replace(/\+/g, ' '));

    const useCase = new ReceiveMailUseCase({
      storageRepository: new S3StorageRepository(bucket),
      emailParser: new SimpleEmailParser(),
      onEmailReceived: createEmailReceivedHandler(app, process.env.SLACK_CHANNEL_ID!),
    });

    await useCase.execute({ storageKey: key });
  }
};

License

MIT