Skip to content

Commit 27acd7b

Browse files
jtesowtfsayo
andauthored
feat: add email-plugin (#2645)
* feat: add email capability * add initialization + update .env.example * fix build issues and update lock file * Update pnpm-lock.yaml --------- Co-authored-by: Sayo <hi@sayo.wtf> Co-authored-by: Sayo <82053242+wtfsayo@users.noreply.github.com>
1 parent 248fbe2 commit 27acd7b

21 files changed

+1150
-544
lines changed

.env.example

+16
Original file line numberDiff line numberDiff line change
@@ -761,3 +761,19 @@ NVIDIA_COSMOS_MODEL=nvidia/cosmos-nemotron-34b
761761
NVIDIA_COSMOS_INVOKE_URL=https://ai.api.nvidia.com/v1/vlm/nvidia/cosmos-nemotron-34b
762762
NVIDIA_COSMOS_ASSET_URL=https://api.nvcf.nvidia.com/v2/nvcf/assets
763763
NVIDIA_COSMOS_MAX_TOKENS=1000
764+
765+
# Email Plugin Configuration
766+
767+
# Outgoing Email Settings (SMTP/Gmail)
768+
EMAIL_OUTGOING_SERVICE=smtp # Use "smtp" or "gmail"
769+
EMAIL_OUTGOING_HOST=smtp.example.com # Required for SMTP only
770+
EMAIL_OUTGOING_PORT=465 # Default 465 for secure SMTP, 587 for TLS
771+
EMAIL_OUTGOING_USER=
772+
EMAIL_OUTGOING_PASS= # For Gmail, use App Password
773+
774+
# Incoming Email Settings (IMAP)
775+
EMAIL_INCOMING_SERVICE=imap
776+
EMAIL_INCOMING_HOST=imap.example.com
777+
EMAIL_INCOMING_PORT=993 # Default port for secure IMAP
778+
EMAIL_INCOMING_USER=
779+
EMAIL_INCOMING_PASS=

.github/workflows/integrationTests.yaml

+1-4
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,8 @@ jobs:
2424
node-version: "23.3"
2525
cache: "pnpm"
2626

27-
- name: Clean up
28-
run: pnpm clean
29-
3027
- name: Install dependencies
31-
run: pnpm install -r --no-frozen-lockfile
28+
run: pnpm install --no-frozen-lockfile
3229

3330
- name: Build packages
3431
run: pnpm build

agent/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
"@elizaos/plugin-nvidia-nim": "workspace:*",
116116
"@elizaos/plugin-0x": "workspace:*",
117117
"@elizaos/plugin-dkg": "workspace:*",
118+
"@elizaos/plugin-email": "workspace:*",
118119
"readline": "1.3.0",
119120
"ws": "8.18.0",
120121
"yargs": "17.7.2"

agent/src/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ import net from "net";
126126
import path from "path";
127127
import { fileURLToPath } from "url";
128128
import yargs from "yargs";
129+
import { emailPlugin } from "@elizaos/plugin-email";
129130

130131
const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
131132
const __dirname = path.dirname(__filename); // get the name of the directory
@@ -1124,6 +1125,9 @@ export async function createAgent(
11241125
getSecret(character, "BNB_PUBLIC_KEY")?.startsWith("0x")
11251126
? bnbPlugin
11261127
: null,
1128+
getSecret(character, "EMAIL_INCOMING_USER") && getSecret(character, "EMAIL_INCOMING_PASS") ||
1129+
getSecret(character, "EMAIL_OUTGOING_USER") && getSecret(character, "EMAIL_OUTGOING_PASS") ?
1130+
emailPlugin : null
11271131
].filter(Boolean),
11281132
providers: [],
11291133
actions: [],

package.json

+78-73
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,79 @@
11
{
2-
"name": "eliza",
3-
"scripts": {
4-
"format": "biome format --write .",
5-
"lint": "biome lint .",
6-
"check": "biome check --apply .",
7-
"preinstall": "npx only-allow pnpm",
8-
"build": "turbo run build --filter=!eliza-docs",
9-
"build-docker": "turbo run build",
10-
"cleanstart": "if [ -f agent/data/db.sqlite ]; then rm agent/data/db.sqlite; fi && pnpm --filter \"@elizaos/agent\" start --isRoot",
11-
"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",
12-
"start": "pnpm --filter \"@elizaos/agent\" start --isRoot",
13-
"start:client": "pnpm --dir client dev",
14-
"start:debug": "cross-env NODE_ENV=development VERBOSE=true DEFAULT_LOG_LEVEL=debug DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot",
15-
"dev": "bash ./scripts/dev.sh",
16-
"release": "pnpm build && pnpm format && npx lerna publish --no-private --force-publish",
17-
"clean": "bash ./scripts/clean.sh",
18-
"docker:build": "bash ./scripts/docker.sh build",
19-
"docker:run": "bash ./scripts/docker.sh run",
20-
"docker:bash": "bash ./scripts/docker.sh bash",
21-
"docker:start": "bash ./scripts/docker.sh start",
22-
"docker": "pnpm docker:build && pnpm docker:run && pnpm docker:bash",
23-
"test": "bash ./scripts/test.sh",
24-
"smokeTests": "bash ./scripts/smokeTests.sh",
25-
"integrationTests": "bash ./scripts/integrationTests.sh"
26-
},
27-
"devDependencies": {
28-
"@biomejs/biome": "^1.9.4",
29-
"@commitlint/cli": "18.6.1",
30-
"@commitlint/config-conventional": "18.6.3",
31-
"@types/jest": "^29.5.11",
32-
"concurrently": "9.1.0",
33-
"cross-env": "7.0.3",
34-
"husky": "9.1.7",
35-
"jest": "^29.7.0",
36-
"lerna": "8.1.5",
37-
"only-allow": "1.2.1",
38-
"turbo": "2.3.3",
39-
"typedoc": "0.26.11",
40-
"typescript": "5.6.3",
41-
"viem": "2.21.58",
42-
"vite": "5.4.12",
43-
"vitest": "2.1.5"
44-
},
45-
"pnpm": {
46-
"overrides": {
47-
"onnxruntime-node": "1.20.1",
48-
"viem": "2.21.58"
49-
}
50-
},
51-
"engines": {
52-
"node": "23.3.0"
53-
},
54-
"dependencies": {
55-
"@0glabs/0g-ts-sdk": "0.2.1",
56-
"@coinbase/coinbase-sdk": "0.10.0",
57-
"@deepgram/sdk": "^3.9.0",
58-
"@injectivelabs/sdk-ts": "^1.14.33",
59-
"@vitest/eslint-plugin": "1.0.1",
60-
"amqplib": "0.10.5",
61-
"csv-parse": "5.6.0",
62-
"langdetect": "^0.2.1",
63-
"ollama-ai-provider": "0.16.1",
64-
"optional": "0.1.4",
65-
"pnpm": "9.14.4",
66-
"sharp": "0.33.5",
67-
"tslog": "4.9.3",
68-
"bs58": "4.0.0"
69-
},
70-
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
71-
"workspaces": [
72-
"packages/*"
73-
]
74-
}
2+
3+
"name": "eliza",
4+
"scripts": {
5+
"format": "biome format --write .",
6+
"lint": "biome lint .",
7+
"check": "biome check --apply .",
8+
"preinstall": "npx only-allow pnpm",
9+
"build": "turbo run build --filter=!eliza-docs",
10+
"build-docker": "turbo run build",
11+
"cleanstart": "if [ -f agent/data/db.sqlite ]; then rm agent/data/db.sqlite; fi && pnpm --filter \"@elizaos/agent\" start --isRoot",
12+
"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",
13+
"start": "pnpm --filter \"@elizaos/agent\" start --isRoot",
14+
"start:client": "pnpm --dir client dev",
15+
"start:debug": "cross-env NODE_ENV=development VERBOSE=true DEBUG=eliza:* pnpm --filter \"@elizaos/agent\" start --isRoot",
16+
"dev": "bash ./scripts/dev.sh",
17+
"release": "pnpm build && pnpm format && npx lerna publish --no-private --force-publish",
18+
"clean": "bash ./scripts/clean.sh",
19+
"docker:build": "bash ./scripts/docker.sh build",
20+
"docker:run": "bash ./scripts/docker.sh run",
21+
"docker:bash": "bash ./scripts/docker.sh bash",
22+
"docker:start": "bash ./scripts/docker.sh start",
23+
"docker": "pnpm docker:build && pnpm docker:run && pnpm docker:bash",
24+
"test": "bash ./scripts/test.sh",
25+
"smokeTests": "bash ./scripts/smokeTests.sh",
26+
"integrationTests": "bash ./scripts/integrationTests.sh"
27+
},
28+
"devDependencies": {
29+
"@biomejs/biome": "^1.9.4",
30+
"@commitlint/cli": "18.6.1",
31+
"@commitlint/config-conventional": "18.6.3",
32+
"@types/jest": "^29.5.11",
33+
"concurrently": "9.1.0",
34+
"cross-env": "7.0.3",
35+
"husky": "9.1.7",
36+
"jest": "^29.7.0",
37+
"lerna": "8.1.5",
38+
"only-allow": "1.2.1",
39+
"turbo": "2.3.3",
40+
"typedoc": "0.26.11",
41+
"typescript": "5.6.3",
42+
"viem": "2.21.58",
43+
"vite": "5.4.12",
44+
"vitest": "2.1.5"
45+
},
46+
"pnpm": {
47+
"overrides": {
48+
"onnxruntime-node": "1.20.1",
49+
"viem": "2.21.58",
50+
"@polkadot/util": "12.6.2",
51+
"@polkadot/util-crypto": "12.6.2",
52+
"@polkadot/types-create": "10.13.1",
53+
"@polkadot/types-codec": "10.13.1"
54+
}
55+
},
56+
"engines": {
57+
"node": "23.3.0"
58+
},
59+
"dependencies": {
60+
"@0glabs/0g-ts-sdk": "0.2.1",
61+
"@coinbase/coinbase-sdk": "0.10.0",
62+
"@deepgram/sdk": "^3.9.0",
63+
"@injectivelabs/sdk-ts": "^1.14.33",
64+
"@vitest/eslint-plugin": "1.0.1",
65+
"amqplib": "0.10.5",
66+
"csv-parse": "5.6.0",
67+
"langdetect": "^0.2.1",
68+
"ollama-ai-provider": "0.16.1",
69+
"optional": "0.1.4",
70+
"pnpm": "9.14.4",
71+
"sharp": "0.33.5",
72+
"tslog": "4.9.3",
73+
"bs58": "4.0.0"
74+
},
75+
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
76+
"workspaces": [
77+
"packages/*"
78+
]
79+
}

packages/plugin-avail/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
"avail-js-sdk": "^0.3.0"
1010
},
1111
"devDependencies": {
12+
"@types/node": "^20.0.0",
1213
"tsup": "8.3.5",
13-
"@types/node": "^20.0.0"
14+
"@polkadot/types": "^10.11.3"
1415
},
1516
"scripts": {
1617
"build": "tsup --format esm --dts",

packages/plugin-avail/src/actions/submitData.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import {
1717
initialize,
1818
getKeyringFromSeed,
1919
} from "avail-js-sdk";
20-
import type { ISubmittableResult } from "@polkadot/types/types/extrinsic";
2120
import type { H256 } from "@polkadot/types/interfaces/runtime";
21+
import { ISubmittableResult } from "@polkadot/types/types";
2222

2323
export interface DataContent extends Content {
2424
data: string;
@@ -134,19 +134,19 @@ export default {
134134
`);
135135

136136
//submit data
137-
const txResult = await new Promise<ISubmittableResult>(
137+
const txResult:ISubmittableResult = await new Promise(
138138
(res) => {
139139
api.tx.dataAvailability
140140
.submitData(data)
141141
.signAndSend(
142142
keyring,
143143
options,
144-
(result: ISubmittableResult) => {
144+
(result) => {
145145
elizaLogger.log(
146146
`Tx status: ${result.status}`
147147
);
148148
if (result.isFinalized || result.isError) {
149-
res(result);
149+
res(result as any);
150150
}
151151
}
152152
);

packages/plugin-avail/src/actions/transfer.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -144,19 +144,19 @@ export default {
144144
);
145145

146146
// Transaction call
147-
const txResult = await new Promise<ISubmittableResult>(
147+
const txResult:ISubmittableResult = await new Promise(
148148
(res) => {
149149
api.tx.balances
150150
.transferKeepAlive(content.recipient, amount)
151151
.signAndSend(
152152
keyring,
153153
options,
154-
(result: ISubmittableResult) => {
154+
(result) => {
155155
elizaLogger.log(
156156
`Tx status: ${result.status}`
157157
);
158158
if (result.isFinalized || result.isError) {
159-
res(result);
159+
res(result as any);
160160
}
161161
}
162162
);

packages/plugin-email/README.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Description
2+
3+
Implementation of a EmailClient for Eliza.
4+
5+
# Settings
6+
7+
The following settings will be declared on your environment variable or inside your agent' settings:
8+
9+
## SMTP Section
10+
11+
- `EMAIL_OUTGOING_SERVICE`: "smtp" | "gmail"
12+
- `EMAIL_OUTGOING_HOST`: SMTP Hostname or IP to connect to. Required only when "smtp" service is configured.
13+
- `EMAIL_OUTGOING_PORT`: the port to connect to (defaults to 465 for secure connections, otherwise 587). Required only if "smtp" is configured.
14+
- `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.
15+
- `EMAIL_OUTGOING_USER`: Username
16+
- `EMAIL_OUTGOING_PASS`: Password. If "gmail" selected you will need to provision a dedicated password for the agent [1]
17+
18+
## IMAP Section
19+
20+
- `EMAIL_INCOMING_SERVICE`: "imap"
21+
- `EMAIL_INCOMING_HOST`: IMAP Hostname or IP to conenct to
22+
- `EMAIL_INCOMING_PORT`: the port to connect to (defaults to 993)
23+
- `EMAIL_INCOMING_USER`: Username
24+
- `EMAIL_INCOMING_PASS`: Password
25+
26+
[1] https://support.google.com/mail/answer/185833?hl=en
27+
28+
## Usage
29+
30+
1. Install the Plugin: First, import the plugin into your agent by running the following command:
31+
32+
```
33+
pnpm add @elizaos/plugin-email
34+
```
35+
36+
2. Send Emails: You can send emails using the following method:
37+
38+
```
39+
this.runtime.clients.email.send({
40+
to: "recipient@example.com",
41+
subject: "Your Subject Here",
42+
text: "Your email body here."
43+
});
44+
```
45+
46+
3. Receive Emails: To receive emails, register a callback function that will be invoked when an email is received:
47+
48+
```
49+
this.runtime.clients.email.receive((email) => {
50+
console.log("Email Received:", email);
51+
});
52+
```
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import eslintGlobalConfig from "../../eslint.config.mjs";
2+
3+
export default [...eslintGlobalConfig];

packages/plugin-email/package.json

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "@elizaos/plugin-email",
3+
"version": "0.1.0",
4+
"type": "module",
5+
"main": "./dist/index.js",
6+
"module": "dist/index.js",
7+
"types": "./dist/index.d.ts",
8+
"scripts": {
9+
"build": "tsup --format esm --dts",
10+
"test": "jest",
11+
"lint": "eslint --fix --cache ."
12+
},
13+
"dependencies": {
14+
"@elizaos/adapter-postgres": "workspace:^",
15+
"@elizaos/core": "workspace:^",
16+
"mail-notifier": "^0.5.0",
17+
"nodemailer": "^6.9.16"
18+
},
19+
"exports": {
20+
"./package.json": "./package.json",
21+
".": {
22+
"import": {
23+
"@elizaos/source": "./src/index.ts",
24+
"types": "./dist/index.d.ts",
25+
"default": "./dist/index.js"
26+
}
27+
}
28+
},
29+
"devDependencies": {
30+
"@types/jest": "^29.5.14",
31+
"@types/mail-notifier": "0.5.2",
32+
"@types/node": "^20.0.0",
33+
"@types/nodemailer": "^6.4.17",
34+
"jest": "^29.7.0",
35+
"ts-jest": "^29.2.5",
36+
"ts-jest-mock-import-meta": "^1.2.1",
37+
"typescript": "^5.0.0"
38+
}
39+
}

0 commit comments

Comments
 (0)