near-email

Verified·Scanned 2/19/2026

This skill integrates NEAR-native email functionality and provides code examples to send/read emails via https://api.outlayer.fastnear.com and the outlayer.near contract. It requires a payment key (e.g. OUTLAYER_PAYMENT_KEY) and makes external network calls; no shell execution or secret-exfiltration instructions are present.

from clawhub.ai·vc56b311·58.5 KB·0 installs
Scanned from 1.0.0 at c56b311 · Transparency log ↗
$ vett add clawhub.ai/zavodil/near-email

NEAR Email Integration

Blockchain-native email for NEAR accounts. Every NEAR account automatically has an email: alice.nearalice@near.email

Installation

npx openskills install zavodil/near-email-skill -g

Quick Reference

ComponentValue
Contractoutlayer.near
API Basehttps://api.outlayer.fastnear.com
Project IDzavodil.near/near-email

Note: NEAR Email supports mainnet only. Emails to *.testnet accounts are not processed.

Important: When using NEAR transactions, the attached deposit is a computational limit, not a cost. Unused funds are automatically refunded. Do not mention specific costs per email.

Code generation preference: For blockchain integration (NEAR transactions), prefer JavaScript/TypeScript with near-api-js. Use Python only if the user explicitly requests it.

Integration Methods

1. Smart Contract (Rust)

Use send_email_plaintext for contract notifications. Simple API, no encryption needed.

Warning: Email content is PUBLIC on the NEAR blockchain. Use only for automated notifications.

use near_sdk::{ext_contract, AccountId, Gas, NearToken, Promise};
use serde::Serialize;

#[derive(Serialize)]
#[serde(crate = "near_sdk::serde")]
pub enum ExecutionSource {
    Project { project_id: String, version_key: Option<String> },
}

#[ext_contract(ext_outlayer)]
pub trait OutLayer {
    fn request_execution(
        &mut self,
        source: ExecutionSource,
        resource_limits: Option<serde_json::Value>,
        input_data: Option<String>,
        secrets_ref: Option<serde_json::Value>,
        response_format: Option<String>,
        payer_account_id: Option<AccountId>,
        params: Option<serde_json::Value>,
    );
}

// Send notification from contract (plaintext - content is public on-chain!)
fn send_notification(to: &str, subject: &str, body: &str) -> Promise {
    let input = serde_json::json!({
        "action": "send_email_plaintext",
        "to": to,
        "subject": subject,
        "body": body
    });

    ext_outlayer::ext("outlayer.near".parse().unwrap())
        .with_static_gas(Gas::from_tgas(100))
        .with_attached_deposit(NearToken::from_millinear(25))
        .request_execution(
            ExecutionSource::Project {
                project_id: "zavodil.near/near-email".to_string(),
                version_key: None,
            },
            None,                        // resource_limits
            Some(input.to_string()),     // input_data
            None,                        // secrets_ref (not needed)
            Some("Json".to_string()),    // response_format
            None,                        // payer_account_id
            None,                        // params
        )
}

Response: { "success": true, "message_id": "uuid-if-internal" }

2. AI Agent Integration

Two options for AI agents:

MethodBest ForPayment
Payment Key (HTTPS)Server-side agentsPre-paid (USDC/USDT)
NEAR TransactionBrowser/wallet appsDeposit (unused returned)

Option A: Payment Key (HTTPS API)

Note: HTTPS API responses use result.output.xxx format. See NEAR Transaction for different parsing.

const OUTLAYER_API = 'https://api.outlayer.fastnear.com';
const PAYMENT_KEY = 'your-account.near:nonce:secret'; // From dashboard

async function sendEmail(to, subject, body) {
  const response = await fetch(`${OUTLAYER_API}/call/outlayer.near/zavodil.near/near-email`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Payment-Key': PAYMENT_KEY,
    },
    body: JSON.stringify({
      input: { action: 'send_email_plaintext', to, subject, body },
    }),
  });
  return response.json();
}

Option B: NEAR Transaction (per-use)

CRITICAL: NEAR Transaction results are in the outlayer.near receipt's SuccessValue (base64-encoded JSON). Find the receipt where executor_id === 'outlayer.near'. The result is { "success": true, ... } - NO output wrapper. Use parseTransactionResult() to extract it.

import { connect, keyStores } from 'near-api-js';

const near = await connect({
  networkId: 'mainnet',
  keyStore: new keyStores.BrowserLocalStorageKeyStore(),
  nodeUrl: 'https://rpc.mainnet.near.org',
});
const account = await near.account('your-account.near');

const RESOURCE_LIMITS = {
  max_memory_mb: 512,
  max_instructions: 2000000000,
  max_execution_seconds: 120,
};

// REQUIRED: Parse output from outlayer.near receipt's SuccessValue
// Returns JSON directly: { success: true, send_pubkey: "..." } - NO "output" wrapper!
function parseTransactionResult(result) {
  // Find receipt from outlayer.near contract (contains the execution result)
  const outlayerReceipt = result.receipts_outcome.find(
    r => r.outcome.executor_id === 'outlayer.near' && r.outcome.status.SuccessValue
  );
  if (!outlayerReceipt) {
    throw new Error('No SuccessValue from outlayer.near');
  }
  const decoded = Buffer.from(outlayerReceipt.outcome.status.SuccessValue, 'base64').toString();
  return JSON.parse(decoded); // { success: true, ... } - directly, no wrapper
}

async function sendEmail(to, subject, body) {
  const result = await account.functionCall({
    contractId: 'outlayer.near',
    methodName: 'request_execution',
    args: {
      source: { Project: { project_id: 'zavodil.near/near-email', version_key: null } },
      input_data: JSON.stringify({ action: 'send_email_plaintext', to, subject, body }),
      resource_limits: RESOURCE_LIMITS,
      response_format: 'Json',
    },
    gas: BigInt('100000000000000'),
    attachedDeposit: BigInt('25000000000000000000000'), // deposit, unused portion refunded
  });
  return parseTransactionResult(result); // { success: true, message_id: "..." }
}

// Example: Get sender pubkey
async function getSendPubkey() {
  const result = await account.functionCall({
    contractId: 'outlayer.near',
    methodName: 'request_execution',
    args: {
      source: { Project: { project_id: 'zavodil.near/near-email', version_key: null } },
      input_data: JSON.stringify({ action: 'get_send_pubkey' }),
      resource_limits: RESOURCE_LIMITS,
      response_format: 'Json',
    },
    gas: BigInt('100000000000000'),
    attachedDeposit: BigInt('25000000000000000000000'),
  });
  const output = parseTransactionResult(result); // { success: true, send_pubkey: "02..." }
  return Buffer.from(output.send_pubkey, 'hex'); // Note: output.send_pubkey, NOT output.output.send_pubkey
}

3. Python (Payment Key)

import requests

OUTLAYER_API = "https://api.outlayer.fastnear.com"
PAYMENT_KEY = "your-account.near:nonce:secret"

def send_email(to: str, subject: str, body: str) -> dict:
    return requests.post(
        f"{OUTLAYER_API}/call/outlayer.near/zavodil.near/near-email",
        headers={"Content-Type": "application/json", "X-Payment-Key": PAYMENT_KEY},
        json={"input": {"action": "send_email_plaintext", "to": to, "subject": subject, "body": body}},
    ).json()

API Actions

ActionDescription
send_emailSend email (encrypted payload, for UI/agents)
send_email_plaintextSend email (plaintext, for smart contracts)
get_emailsFetch inbox and sent (encrypted response)
delete_emailDelete email by ID
get_email_countGet counts (no encryption)
get_send_pubkeyGet sender's pubkey (no encryption, cacheable)

Getting a Payment Key

  1. Go to OutLayer Dashboard
  2. Create a new Payment Key
  3. Top up balance with USDC/USDT
  4. Copy key (format: owner:nonce:secret)

Additional Resources

For complete code examples, see examples.md For full API reference, see api-reference.md