Skip to content

Commit

Permalink
feat: add email-plugin (elizaOS#2645)
Browse files Browse the repository at this point in the history
* feat: add email capability

* add initialization + update .env.example

* fix build issues and update lock file

* Update pnpm-lock.yaml

---------

Co-authored-by: Sayo <[email protected]>
Co-authored-by: Sayo <[email protected]>
  • Loading branch information
3 people authored Jan 22, 2025
1 parent 248fbe2 commit 27acd7b
Show file tree
Hide file tree
Showing 21 changed files with 1,150 additions and 544 deletions.
16 changes: 16 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -761,3 +761,19 @@ NVIDIA_COSMOS_MODEL=nvidia/cosmos-nemotron-34b
NVIDIA_COSMOS_INVOKE_URL=https://ai.api.nvidia.com/v1/vlm/nvidia/cosmos-nemotron-34b
NVIDIA_COSMOS_ASSET_URL=https://api.nvcf.nvidia.com/v2/nvcf/assets
NVIDIA_COSMOS_MAX_TOKENS=1000

# Email Plugin Configuration

# Outgoing Email Settings (SMTP/Gmail)
EMAIL_OUTGOING_SERVICE=smtp # Use "smtp" or "gmail"
EMAIL_OUTGOING_HOST=smtp.example.com # Required for SMTP only
EMAIL_OUTGOING_PORT=465 # Default 465 for secure SMTP, 587 for TLS
EMAIL_OUTGOING_USER=
EMAIL_OUTGOING_PASS= # For Gmail, use App Password

# Incoming Email Settings (IMAP)
EMAIL_INCOMING_SERVICE=imap
EMAIL_INCOMING_HOST=imap.example.com
EMAIL_INCOMING_PORT=993 # Default port for secure IMAP
EMAIL_INCOMING_USER=
EMAIL_INCOMING_PASS=
5 changes: 1 addition & 4 deletions .github/workflows/integrationTests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@ jobs:
node-version: "23.3"
cache: "pnpm"

- name: Clean up
run: pnpm clean

- name: Install dependencies
run: pnpm install -r --no-frozen-lockfile
run: pnpm install --no-frozen-lockfile

- name: Build packages
run: pnpm build
Expand Down
1 change: 1 addition & 0 deletions agent/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"@elizaos/plugin-nvidia-nim": "workspace:*",
"@elizaos/plugin-0x": "workspace:*",
"@elizaos/plugin-dkg": "workspace:*",
"@elizaos/plugin-email": "workspace:*",
"readline": "1.3.0",
"ws": "8.18.0",
"yargs": "17.7.2"
Expand Down
4 changes: 4 additions & 0 deletions agent/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ import net from "net";
import path from "path";
import { fileURLToPath } from "url";
import yargs from "yargs";
import { emailPlugin } from "@elizaos/plugin-email";

const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
const __dirname = path.dirname(__filename); // get the name of the directory
Expand Down Expand Up @@ -1124,6 +1125,9 @@ export async function createAgent(
getSecret(character, "BNB_PUBLIC_KEY")?.startsWith("0x")
? bnbPlugin
: null,
getSecret(character, "EMAIL_INCOMING_USER") && getSecret(character, "EMAIL_INCOMING_PASS") ||
getSecret(character, "EMAIL_OUTGOING_USER") && getSecret(character, "EMAIL_OUTGOING_PASS") ?
emailPlugin : null
].filter(Boolean),
providers: [],
actions: [],
Expand Down
151 changes: 78 additions & 73 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,74 +1,79 @@
{
"name": "eliza",
"scripts": {
"format": "biome format --write .",
"lint": "biome lint .",
"check": "biome check --apply .",
"preinstall": "npx only-allow pnpm",
"build": "turbo run build --filter=!eliza-docs",
"build-docker": "turbo run build",
"cleanstart": "if [ -f agent/data/db.sqlite ]; then rm agent/data/db.sqlite; fi && pnpm --filter \"@elizaos/agent\" start --isRoot",
"cleanstart:debug": "if [ -f agent/data/db.sqlite ]; then rm agent/data/db.sqlite; fi && cross-env NODE_ENV=development VERBOSE=true DEFAULT_LOG_LEVEL=debug DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot",
"start": "pnpm --filter \"@elizaos/agent\" start --isRoot",
"start:client": "pnpm --dir client dev",
"start:debug": "cross-env NODE_ENV=development VERBOSE=true DEFAULT_LOG_LEVEL=debug DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot",
"dev": "bash ./scripts/dev.sh",
"release": "pnpm build && pnpm format && npx lerna publish --no-private --force-publish",
"clean": "bash ./scripts/clean.sh",
"docker:build": "bash ./scripts/docker.sh build",
"docker:run": "bash ./scripts/docker.sh run",
"docker:bash": "bash ./scripts/docker.sh bash",
"docker:start": "bash ./scripts/docker.sh start",
"docker": "pnpm docker:build && pnpm docker:run && pnpm docker:bash",
"test": "bash ./scripts/test.sh",
"smokeTests": "bash ./scripts/smokeTests.sh",
"integrationTests": "bash ./scripts/integrationTests.sh"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@commitlint/cli": "18.6.1",
"@commitlint/config-conventional": "18.6.3",
"@types/jest": "^29.5.11",
"concurrently": "9.1.0",
"cross-env": "7.0.3",
"husky": "9.1.7",
"jest": "^29.7.0",
"lerna": "8.1.5",
"only-allow": "1.2.1",
"turbo": "2.3.3",
"typedoc": "0.26.11",
"typescript": "5.6.3",
"viem": "2.21.58",
"vite": "5.4.12",
"vitest": "2.1.5"
},
"pnpm": {
"overrides": {
"onnxruntime-node": "1.20.1",
"viem": "2.21.58"
}
},
"engines": {
"node": "23.3.0"
},
"dependencies": {
"@0glabs/0g-ts-sdk": "0.2.1",
"@coinbase/coinbase-sdk": "0.10.0",
"@deepgram/sdk": "^3.9.0",
"@injectivelabs/sdk-ts": "^1.14.33",
"@vitest/eslint-plugin": "1.0.1",
"amqplib": "0.10.5",
"csv-parse": "5.6.0",
"langdetect": "^0.2.1",
"ollama-ai-provider": "0.16.1",
"optional": "0.1.4",
"pnpm": "9.14.4",
"sharp": "0.33.5",
"tslog": "4.9.3",
"bs58": "4.0.0"
},
"packageManager": "[email protected]+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
"workspaces": [
"packages/*"
]
}

"name": "eliza",
"scripts": {
"format": "biome format --write .",
"lint": "biome lint .",
"check": "biome check --apply .",
"preinstall": "npx only-allow pnpm",
"build": "turbo run build --filter=!eliza-docs",
"build-docker": "turbo run build",
"cleanstart": "if [ -f agent/data/db.sqlite ]; then rm agent/data/db.sqlite; fi && pnpm --filter \"@elizaos/agent\" start --isRoot",
"cleanstart:debug": "if [ -f agent/data/db.sqlite ]; then rm agent/data/db.sqlite; fi && cross-env NODE_ENV=development VERBOSE=true DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot",
"start": "pnpm --filter \"@elizaos/agent\" start --isRoot",
"start:client": "pnpm --dir client dev",
"start:debug": "cross-env NODE_ENV=development VERBOSE=true DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot",
"dev": "bash ./scripts/dev.sh",
"release": "pnpm build && pnpm format && npx lerna publish --no-private --force-publish",
"clean": "bash ./scripts/clean.sh",
"docker:build": "bash ./scripts/docker.sh build",
"docker:run": "bash ./scripts/docker.sh run",
"docker:bash": "bash ./scripts/docker.sh bash",
"docker:start": "bash ./scripts/docker.sh start",
"docker": "pnpm docker:build && pnpm docker:run && pnpm docker:bash",
"test": "bash ./scripts/test.sh",
"smokeTests": "bash ./scripts/smokeTests.sh",
"integrationTests": "bash ./scripts/integrationTests.sh"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@commitlint/cli": "18.6.1",
"@commitlint/config-conventional": "18.6.3",
"@types/jest": "^29.5.11",
"concurrently": "9.1.0",
"cross-env": "7.0.3",
"husky": "9.1.7",
"jest": "^29.7.0",
"lerna": "8.1.5",
"only-allow": "1.2.1",
"turbo": "2.3.3",
"typedoc": "0.26.11",
"typescript": "5.6.3",
"viem": "2.21.58",
"vite": "5.4.12",
"vitest": "2.1.5"
},
"pnpm": {
"overrides": {
"onnxruntime-node": "1.20.1",
"viem": "2.21.58",
"@polkadot/util": "12.6.2",
"@polkadot/util-crypto": "12.6.2",
"@polkadot/types-create": "10.13.1",
"@polkadot/types-codec": "10.13.1"
}
},
"engines": {
"node": "23.3.0"
},
"dependencies": {
"@0glabs/0g-ts-sdk": "0.2.1",
"@coinbase/coinbase-sdk": "0.10.0",
"@deepgram/sdk": "^3.9.0",
"@injectivelabs/sdk-ts": "^1.14.33",
"@vitest/eslint-plugin": "1.0.1",
"amqplib": "0.10.5",
"csv-parse": "5.6.0",
"langdetect": "^0.2.1",
"ollama-ai-provider": "0.16.1",
"optional": "0.1.4",
"pnpm": "9.14.4",
"sharp": "0.33.5",
"tslog": "4.9.3",
"bs58": "4.0.0"
},
"packageManager": "[email protected]+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
"workspaces": [
"packages/*"
]
}
3 changes: 2 additions & 1 deletion packages/plugin-avail/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
"avail-js-sdk": "^0.3.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"tsup": "8.3.5",
"@types/node": "^20.0.0"
"@polkadot/types": "^10.11.3"
},
"scripts": {
"build": "tsup --format esm --dts",
Expand Down
8 changes: 4 additions & 4 deletions packages/plugin-avail/src/actions/submitData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
initialize,
getKeyringFromSeed,
} from "avail-js-sdk";
import type { ISubmittableResult } from "@polkadot/types/types/extrinsic";
import type { H256 } from "@polkadot/types/interfaces/runtime";
import { ISubmittableResult } from "@polkadot/types/types";

export interface DataContent extends Content {
data: string;
Expand Down Expand Up @@ -134,19 +134,19 @@ export default {
`);

//submit data
const txResult = await new Promise<ISubmittableResult>(
const txResult:ISubmittableResult = await new Promise(
(res) => {
api.tx.dataAvailability
.submitData(data)
.signAndSend(
keyring,
options,
(result: ISubmittableResult) => {
(result) => {
elizaLogger.log(
`Tx status: ${result.status}`
);
if (result.isFinalized || result.isError) {
res(result);
res(result as any);
}
}
);
Expand Down
6 changes: 3 additions & 3 deletions packages/plugin-avail/src/actions/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,19 +144,19 @@ export default {
);

// Transaction call
const txResult = await new Promise<ISubmittableResult>(
const txResult:ISubmittableResult = await new Promise(
(res) => {
api.tx.balances
.transferKeepAlive(content.recipient, amount)
.signAndSend(
keyring,
options,
(result: ISubmittableResult) => {
(result) => {
elizaLogger.log(
`Tx status: ${result.status}`
);
if (result.isFinalized || result.isError) {
res(result);
res(result as any);
}
}
);
Expand Down
52 changes: 52 additions & 0 deletions packages/plugin-email/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Description

Implementation of a EmailClient for Eliza.

# Settings

The following settings will be declared on your environment variable or inside your agent' settings:

## SMTP Section

- `EMAIL_OUTGOING_SERVICE`: "smtp" | "gmail"
- `EMAIL_OUTGOING_HOST`: SMTP Hostname or IP to connect to. Required only when "smtp" service is configured.
- `EMAIL_OUTGOING_PORT`: the port to connect to (defaults to 465 for secure connections, otherwise 587). Required only if "smtp" is configured.
- `EMAIL_SECURE`: if true the connection will use TLS, otherwise TLS will be used if server supports STARTLS extension. Set to true if port 465 is selected.
- `EMAIL_OUTGOING_USER`: Username
- `EMAIL_OUTGOING_PASS`: Password. If "gmail" selected you will need to provision a dedicated password for the agent [1]

## IMAP Section

- `EMAIL_INCOMING_SERVICE`: "imap"
- `EMAIL_INCOMING_HOST`: IMAP Hostname or IP to conenct to
- `EMAIL_INCOMING_PORT`: the port to connect to (defaults to 993)
- `EMAIL_INCOMING_USER`: Username
- `EMAIL_INCOMING_PASS`: Password

[1] https://support.google.com/mail/answer/185833?hl=en

## Usage

1. Install the Plugin: First, import the plugin into your agent by running the following command:

```
pnpm add @elizaos/plugin-email
```

2. Send Emails: You can send emails using the following method:

```
this.runtime.clients.email.send({
to: "[email protected]",
subject: "Your Subject Here",
text: "Your email body here."
});
```

3. Receive Emails: To receive emails, register a callback function that will be invoked when an email is received:

```
this.runtime.clients.email.receive((email) => {
console.log("Email Received:", email);
});
```
3 changes: 3 additions & 0 deletions packages/plugin-email/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import eslintGlobalConfig from "../../eslint.config.mjs";

export default [...eslintGlobalConfig];
39 changes: 39 additions & 0 deletions packages/plugin-email/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@elizaos/plugin-email",
"version": "0.1.0",
"type": "module",
"main": "./dist/index.js",
"module": "dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsup --format esm --dts",
"test": "jest",
"lint": "eslint --fix --cache ."
},
"dependencies": {
"@elizaos/adapter-postgres": "workspace:^",
"@elizaos/core": "workspace:^",
"mail-notifier": "^0.5.0",
"nodemailer": "^6.9.16"
},
"exports": {
"./package.json": "./package.json",
".": {
"import": {
"@elizaos/source": "./src/index.ts",
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
},
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/mail-notifier": "0.5.2",
"@types/node": "^20.0.0",
"@types/nodemailer": "^6.4.17",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
"ts-jest-mock-import-meta": "^1.2.1",
"typescript": "^5.0.0"
}
}
Loading

0 comments on commit 27acd7b

Please sign in to comment.