agentmail 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Client.js +2 -2
- package/dist/cjs/api/resources/domains/types/Domain.d.ts +1 -0
- package/dist/cjs/api/resources/domains/types/DomainItem.d.ts +1 -0
- package/dist/cjs/api/resources/inboxes/types/Inbox.d.ts +1 -0
- package/dist/cjs/api/resources/messages/types/ReplyToMessageRequest.d.ts +1 -0
- package/dist/cjs/api/resources/messages/types/SendMessageHeaders.d.ts +4 -0
- package/dist/cjs/api/resources/messages/types/SendMessageHeaders.js +3 -0
- package/dist/cjs/api/resources/messages/types/SendMessageRequest.d.ts +1 -0
- package/dist/cjs/api/resources/messages/types/index.d.ts +1 -0
- package/dist/cjs/api/resources/messages/types/index.js +1 -0
- package/dist/cjs/serialization/resources/domains/types/Domain.d.ts +2 -0
- package/dist/cjs/serialization/resources/domains/types/Domain.js +2 -0
- package/dist/cjs/serialization/resources/domains/types/DomainItem.d.ts +2 -0
- package/dist/cjs/serialization/resources/domains/types/DomainItem.js +2 -0
- package/dist/cjs/serialization/resources/inboxes/types/Inbox.d.ts +2 -0
- package/dist/cjs/serialization/resources/inboxes/types/Inbox.js +2 -0
- package/dist/cjs/serialization/resources/messages/types/ReplyToMessageRequest.d.ts +2 -0
- package/dist/cjs/serialization/resources/messages/types/ReplyToMessageRequest.js +2 -0
- package/dist/cjs/serialization/resources/messages/types/SendMessageHeaders.d.ts +7 -0
- package/dist/cjs/serialization/resources/messages/types/SendMessageHeaders.js +39 -0
- package/dist/cjs/serialization/resources/messages/types/SendMessageRequest.d.ts +2 -0
- package/dist/cjs/serialization/resources/messages/types/SendMessageRequest.js +2 -0
- package/dist/cjs/serialization/resources/messages/types/index.d.ts +1 -0
- package/dist/cjs/serialization/resources/messages/types/index.js +1 -0
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/Client.mjs +2 -2
- package/dist/esm/api/resources/domains/types/Domain.d.mts +1 -0
- package/dist/esm/api/resources/domains/types/DomainItem.d.mts +1 -0
- package/dist/esm/api/resources/inboxes/types/Inbox.d.mts +1 -0
- package/dist/esm/api/resources/messages/types/ReplyToMessageRequest.d.mts +1 -0
- package/dist/esm/api/resources/messages/types/SendMessageHeaders.d.mts +4 -0
- package/dist/esm/api/resources/messages/types/SendMessageHeaders.mjs +2 -0
- package/dist/esm/api/resources/messages/types/SendMessageRequest.d.mts +1 -0
- package/dist/esm/api/resources/messages/types/index.d.mts +1 -0
- package/dist/esm/api/resources/messages/types/index.mjs +1 -0
- package/dist/esm/serialization/resources/domains/types/Domain.d.mts +2 -0
- package/dist/esm/serialization/resources/domains/types/Domain.mjs +2 -0
- package/dist/esm/serialization/resources/domains/types/DomainItem.d.mts +2 -0
- package/dist/esm/serialization/resources/domains/types/DomainItem.mjs +2 -0
- package/dist/esm/serialization/resources/inboxes/types/Inbox.d.mts +2 -0
- package/dist/esm/serialization/resources/inboxes/types/Inbox.mjs +2 -0
- package/dist/esm/serialization/resources/messages/types/ReplyToMessageRequest.d.mts +2 -0
- package/dist/esm/serialization/resources/messages/types/ReplyToMessageRequest.mjs +2 -0
- package/dist/esm/serialization/resources/messages/types/SendMessageHeaders.d.mts +7 -0
- package/dist/esm/serialization/resources/messages/types/SendMessageHeaders.mjs +3 -0
- package/dist/esm/serialization/resources/messages/types/SendMessageRequest.d.mts +2 -0
- package/dist/esm/serialization/resources/messages/types/SendMessageRequest.mjs +2 -0
- package/dist/esm/serialization/resources/messages/types/index.d.mts +1 -0
- package/dist/esm/serialization/resources/messages/types/index.mjs +1 -0
- package/dist/esm/version.d.mts +1 -1
- package/dist/esm/version.mjs +1 -1
- package/dist/llms-full.txt +593 -41
- package/dist/llms.txt +1 -0
- package/package.json +1 -1
package/dist/llms-full.txt
CHANGED
|
@@ -171,7 +171,7 @@ This guide will walk you through installing the AgentMail SDK, authenticating wi
|
|
|
171
171
|
<Step title="Create an API Key">
|
|
172
172
|
Now that you're in the console, you'll need to create an API key to
|
|
173
173
|
authenticate your requests. Navigate to the API Keys section in your console
|
|
174
|
-
dashboard.  Click
|
|
175
175
|
"Create New API Key" and give it a descriptive name. Once created, copy the
|
|
176
176
|
API key and store it securely. Create a `.env` file in your project's root
|
|
177
177
|
directory and add your key to it. We recommend using environment variables to
|
|
@@ -312,7 +312,7 @@ Unlike traditional email providers that are designed for human scale, AgentMail
|
|
|
312
312
|
|
|
313
313
|
As the diagram below illustrates, your `organization` is the top-level container that holds all your resources. You can provision many `Inboxes` within your `organization`, each with its own `Threads`, `Messages`, and `Attachments`, allowing you to manage a large fleet of agents seamlessly.
|
|
314
314
|
|
|
315
|
-
<img src="file:
|
|
315
|
+
<img src="file:ac426e5d-2c1a-40b1-bf52-5c97883187df" alt="AgentMail Organizational Hierarchy" />
|
|
316
316
|
|
|
317
317
|
<Steps>
|
|
318
318
|
<Step title="Organization">
|
|
@@ -732,7 +732,7 @@ Here is an example of a well-structured and styled HTML header:
|
|
|
732
732
|
</CodeBlocks>
|
|
733
733
|
|
|
734
734
|
<Frame caption="Look how pretty this message looks!">
|
|
735
|
-
<img src="file:
|
|
735
|
+
<img src="file:3e435f8a-5583-4ddd-83a3-c3f87c5f3aac" alt="rendered css" />
|
|
736
736
|
</Frame>
|
|
737
737
|
|
|
738
738
|
## Receiving `Messages`
|
|
@@ -1759,7 +1759,7 @@ Configuring your domain is a three-step process: add the domain via API, copy th
|
|
|
1759
1759
|
After creating your domain in the AgentMail Console, click the "Download BIND Zone File" button to get the complete zone file.
|
|
1760
1760
|
|
|
1761
1761
|
<Frame caption="Downloading BIND zone file from AgentMail Console">
|
|
1762
|
-
<img src="file:
|
|
1762
|
+
<img src="file:fdcf475d-78f0-49a1-aa38-5bd877368f56" alt="Download BIND Zone File from Console" />
|
|
1763
1763
|
</Frame>
|
|
1764
1764
|
|
|
1765
1765
|
<Tabs>
|
|
@@ -1770,13 +1770,13 @@ Configuring your domain is a three-step process: add the domain via API, copy th
|
|
|
1770
1770
|
2. Click **"Import zone file"** in the top right corner
|
|
1771
1771
|
|
|
1772
1772
|
<Frame caption="Importing BIND zone file in AWS Route 53">
|
|
1773
|
-
<img src="file:
|
|
1773
|
+
<img src="file:01476e8c-76ae-4414-b008-0547631c47f1" alt="AWS Route 53 BIND Import" />
|
|
1774
1774
|
</Frame>
|
|
1775
1775
|
|
|
1776
1776
|
3. Paste the CONTENTS of downloaded BIND zone file
|
|
1777
1777
|
|
|
1778
1778
|
<Frame caption="Open the file with text editor and paste the contents. It should look similar to what we have in this image.">
|
|
1779
|
-
<img src="file:
|
|
1779
|
+
<img src="file:86767929-19ef-4ded-b528-ed42ede218fe" alt="AWS Route 53 BIND Import" />
|
|
1780
1780
|
</Frame>
|
|
1781
1781
|
|
|
1782
1782
|
4. Review the records and click **"Import"**
|
|
@@ -1789,13 +1789,13 @@ Configuring your domain is a three-step process: add the domain via API, copy th
|
|
|
1789
1789
|
2. Navigate to **DNS > Records**
|
|
1790
1790
|
|
|
1791
1791
|
<Frame caption="This is what the page looks like">
|
|
1792
|
-
<img src="file:
|
|
1792
|
+
<img src="file:1886368e-04ae-4bfe-a117-83246de25118" alt="Cloudflare BIND Import" />
|
|
1793
1793
|
</Frame>
|
|
1794
1794
|
|
|
1795
1795
|
3. Click **"Import and Export"**
|
|
1796
1796
|
|
|
1797
1797
|
<Frame caption="You should be able to just drop the file in">
|
|
1798
|
-
<img src="file:
|
|
1798
|
+
<img src="file:b966738e-c0e6-425d-86d1-0ce95b9a326d" alt="Cloudflare BIND Import" />
|
|
1799
1799
|
</Frame>
|
|
1800
1800
|
|
|
1801
1801
|
4. Upload the downloaded BIND zone file as is
|
|
@@ -1808,13 +1808,13 @@ Configuring your domain is a three-step process: add the domain via API, copy th
|
|
|
1808
1808
|
2. Navigate to the **DNS** subtab of the domain you want to send from
|
|
1809
1809
|
|
|
1810
1810
|
<Frame caption="Click on this button!">
|
|
1811
|
-
<img src="file:
|
|
1811
|
+
<img src="file:57da42f8-9541-4e8a-9b20-7c81ca585355" alt="Porkbun DNS Management" />
|
|
1812
1812
|
</Frame>
|
|
1813
1813
|
|
|
1814
1814
|
3. Scroll down to the quick upload section
|
|
1815
1815
|
|
|
1816
1816
|
<Frame caption="Upload your BIND zone file here">
|
|
1817
|
-
<img src="file:
|
|
1817
|
+
<img src="file:2824bdf3-c4c7-4dfe-b67a-1373865ecf22" alt="Porkbun Zone File Import" />
|
|
1818
1818
|
</Frame>
|
|
1819
1819
|
|
|
1820
1820
|
4. Upload the downloaded BIND zone file as is
|
|
@@ -1898,7 +1898,7 @@ Configuring your domain is a three-step process: add the domain via API, copy th
|
|
|
1898
1898
|
* **Value:** Can directly copy paste the `value` from the API response (e.g., `{random_letters_numbers}.dkim.amazonses.com`).
|
|
1899
1899
|
|
|
1900
1900
|
<Frame caption="Example of adding a CNAME record in Route 53. Notice that AWS already appends the root domain (agentmail.cc) to the end of the name value!">
|
|
1901
|
-
<img src="file:
|
|
1901
|
+
<img src="file:62bea4af-5b5e-4f88-86ce-b569f26f8a74" alt="AWS Route 53 Record Configuration" />
|
|
1902
1902
|
</Frame>
|
|
1903
1903
|
|
|
1904
1904
|
* **TXT (DMARC/SPF):**
|
|
@@ -2008,7 +2008,7 @@ DNS can be tricky. Here are some common issues and how to resolve them.
|
|
|
2008
2008
|
|
|
2009
2009
|
## Best Practices for Domain Management
|
|
2010
2010
|
|
|
2011
|
-
Check out our guide on [Email Deliverability](/
|
|
2011
|
+
Check out our guide on [Email Deliverability](/email-deliverability) for tips on warming up your new domain and maintaining a healthy sender reputation.
|
|
2012
2012
|
|
|
2013
2013
|
|
|
2014
2014
|
# Managing Your Domains
|
|
@@ -2434,13 +2434,13 @@ Ngrok creates a secure tunnel from a public URL to your local development server
|
|
|
2434
2434
|
|
|
2435
2435
|
Visit [ngrok.com](https://ngrok.com/) and click "Sign up" to create a free account.
|
|
2436
2436
|
|
|
2437
|
-
<img src="file:
|
|
2437
|
+
<img src="file:845efbdc-7a3b-44be-b7b6-d85c15baabfd" alt="Ngrok homepage" />
|
|
2438
2438
|
|
|
2439
2439
|
### 1.2 Choose your platform and install
|
|
2440
2440
|
|
|
2441
2441
|
After logging in, ngrok will guide you through the setup process. Select your operating system and follow the installation instructions.
|
|
2442
2442
|
|
|
2443
|
-
<img src="file:
|
|
2443
|
+
<img src="file:6bf31cc4-f08c-4b45-9abd-b93966def3ab" alt="Ngrok setup instructions" />
|
|
2444
2444
|
|
|
2445
2445
|
For macOS, you can install ngrok via Homebrew:
|
|
2446
2446
|
|
|
@@ -2486,7 +2486,7 @@ ngrok http 3000
|
|
|
2486
2486
|
|
|
2487
2487
|
You should see output similar to this:
|
|
2488
2488
|
|
|
2489
|
-
<img src="file:
|
|
2489
|
+
<img src="file:190c3920-7025-4399-8718-b2b9a4895382" alt="Ngrok terminal output" />
|
|
2490
2490
|
|
|
2491
2491
|
Copy the **Forwarding URL** (e.g., `https://your-subdomain.ngrok-free.app`). This is the public URL that AgentMail will use to send webhooks.
|
|
2492
2492
|
|
|
@@ -2583,7 +2583,7 @@ python webhook_receiver.py
|
|
|
2583
2583
|
|
|
2584
2584
|
Open your browser and visit `http://127.0.0.1:3000` to see the status page confirming your webhook receiver is running:
|
|
2585
2585
|
|
|
2586
|
-
<img src="file:
|
|
2586
|
+
<img src="file:933ee151-1684-4e56-b2a9-4dd7e81f9f5d" alt="Webhook receiver status page" />
|
|
2587
2587
|
|
|
2588
2588
|
## Testing Your Setup
|
|
2589
2589
|
|
|
@@ -2705,7 +2705,7 @@ How you send your emails is just as important as what you send. If you're sendin
|
|
|
2705
2705
|
more natural to email providers. AgentMail's ability to create inboxes at
|
|
2706
2706
|
scale makes this strategy easy to implement.
|
|
2707
2707
|
|
|
2708
|
-
<img src="file:
|
|
2708
|
+
<img src="file:256ac0e7-42b8-4fdd-a3f1-6136fbec2725" alt="Diagram comparing one inbox sending 1000 emails vs. five inboxes sending 200 each." />
|
|
2709
2709
|
</Step>
|
|
2710
2710
|
|
|
2711
2711
|
<Step title="Protect Your Reputation with Multiple Domains">
|
|
@@ -3293,6 +3293,7 @@ Create a file named `agent.py` and paste the following code:
|
|
|
3293
3293
|
from flask import Flask, request, Response
|
|
3294
3294
|
import ngrok
|
|
3295
3295
|
from agentmail import AgentMail
|
|
3296
|
+
import threading
|
|
3296
3297
|
|
|
3297
3298
|
# Configuration
|
|
3298
3299
|
PORT = 8080
|
|
@@ -3302,6 +3303,7 @@ Create a file named `agent.py` and paste the following code:
|
|
|
3302
3303
|
# Initialize Flask app and AgentMail client
|
|
3303
3304
|
app = Flask(__name__)
|
|
3304
3305
|
client = AgentMail()
|
|
3306
|
+
processed_messages = set() # Track processed message IDs to prevent duplicates
|
|
3305
3307
|
|
|
3306
3308
|
|
|
3307
3309
|
def setup_agentmail():
|
|
@@ -3334,6 +3336,7 @@ Create a file named `agent.py` and paste the following code:
|
|
|
3334
3336
|
webhook = client.webhooks.create(
|
|
3335
3337
|
url=f"{listener.url()}/webhook/agentmail",
|
|
3336
3338
|
event_types=["message.received"],
|
|
3339
|
+
inbox_ids=[inbox.inbox_id],
|
|
3337
3340
|
client_id=f"{INBOX_USERNAME}-webhook"
|
|
3338
3341
|
)
|
|
3339
3342
|
print(f"✓ Webhook created")
|
|
@@ -3361,25 +3364,8 @@ Create a file named `agent.py` and paste the following code:
|
|
|
3361
3364
|
)
|
|
3362
3365
|
|
|
3363
3366
|
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
"""Webhook endpoint to receive incoming email notifications."""
|
|
3367
|
-
payload = request.json
|
|
3368
|
-
event_type = payload.get('type') or payload.get('event_type')
|
|
3369
|
-
|
|
3370
|
-
# Ignore outgoing messages
|
|
3371
|
-
if event_type == 'message.sent':
|
|
3372
|
-
return Response(status=200)
|
|
3373
|
-
|
|
3374
|
-
message = payload.get('message', {})
|
|
3375
|
-
message_id = message.get('message_id')
|
|
3376
|
-
inbox_id = message.get('inbox_id')
|
|
3377
|
-
from_field = message.get('from_', '') or message.get('from', '')
|
|
3378
|
-
|
|
3379
|
-
# Validate required fields
|
|
3380
|
-
if not message_id or not inbox_id or not from_field:
|
|
3381
|
-
return Response(status=200)
|
|
3382
|
-
|
|
3367
|
+
def process_and_reply(message_id, inbox_id, from_field, subject, message):
|
|
3368
|
+
"""Process incoming message and send reply in background."""
|
|
3383
3369
|
# Extract sender email and name
|
|
3384
3370
|
if '<' in from_field and '>' in from_field:
|
|
3385
3371
|
sender_email = from_field.split('<')[1].split('>')[0].strip()
|
|
@@ -3390,10 +3376,8 @@ Create a file named `agent.py` and paste the following code:
|
|
|
3390
3376
|
sender_email = from_field.strip()
|
|
3391
3377
|
sender_name = sender_email.split('@')[0].title() if '@' in sender_email else 'Friend'
|
|
3392
3378
|
|
|
3393
|
-
subject = message.get('subject', '(no subject)')
|
|
3394
|
-
|
|
3395
3379
|
# Log incoming email
|
|
3396
|
-
print(f"
|
|
3380
|
+
print(f"Processing email from {sender_email}: {subject}")
|
|
3397
3381
|
|
|
3398
3382
|
# Generate and send auto-reply
|
|
3399
3383
|
try:
|
|
@@ -3408,6 +3392,41 @@ Create a file named `agent.py` and paste the following code:
|
|
|
3408
3392
|
except Exception as e:
|
|
3409
3393
|
print(f"Error: {e}\n")
|
|
3410
3394
|
|
|
3395
|
+
|
|
3396
|
+
@app.route('/webhook/agentmail', methods=['POST'])
|
|
3397
|
+
def receive_webhook():
|
|
3398
|
+
"""Webhook endpoint to receive incoming email notifications."""
|
|
3399
|
+
payload = request.json
|
|
3400
|
+
event_type = payload.get('type') or payload.get('event_type')
|
|
3401
|
+
|
|
3402
|
+
# Ignore outgoing messages
|
|
3403
|
+
if event_type == 'message.sent':
|
|
3404
|
+
return Response(status=200)
|
|
3405
|
+
|
|
3406
|
+
message = payload.get('message', {})
|
|
3407
|
+
message_id = message.get('message_id')
|
|
3408
|
+
inbox_id = message.get('inbox_id')
|
|
3409
|
+
from_field = message.get('from_', '') or message.get('from', '')
|
|
3410
|
+
|
|
3411
|
+
# Validate required fields
|
|
3412
|
+
if not message_id or not inbox_id or not from_field:
|
|
3413
|
+
return Response(status=200)
|
|
3414
|
+
|
|
3415
|
+
# prevent duplicate
|
|
3416
|
+
if message_id in processed_messages:
|
|
3417
|
+
return Response(status=200)
|
|
3418
|
+
processed_messages.add(message_id)
|
|
3419
|
+
|
|
3420
|
+
subject = message.get('subject', '(no subject)')
|
|
3421
|
+
|
|
3422
|
+
# Process in background thread and return immediately
|
|
3423
|
+
thread = threading.Thread(
|
|
3424
|
+
target=process_and_reply,
|
|
3425
|
+
args=(message_id, inbox_id, from_field, subject, message)
|
|
3426
|
+
)
|
|
3427
|
+
thread.daemon = True
|
|
3428
|
+
thread.start()
|
|
3429
|
+
|
|
3411
3430
|
return Response(status=200)
|
|
3412
3431
|
|
|
3413
3432
|
|
|
@@ -4705,7 +4724,7 @@ Done
|
|
|
4705
4724
|
|
|
4706
4725
|
Go to your AgentMail inbox and filter by labels to organize your emails:
|
|
4707
4726
|
|
|
4708
|
-
<img src="file:
|
|
4727
|
+
<img src="file:0cf3d744-bb78-46de-acc7-e3de13a39cf9" alt="Test image" />
|
|
4709
4728
|
|
|
4710
4729
|
**Filter by sentiment:**
|
|
4711
4730
|
|
|
@@ -4875,12 +4894,545 @@ Ready to build your own intelligent email agent? Check out our [quickstart guide
|
|
|
4875
4894
|
</AccordionGroup>
|
|
4876
4895
|
|
|
4877
4896
|
|
|
4897
|
+
# Email Reply Extraction with Talon
|
|
4898
|
+
|
|
4899
|
+
> Learn how to use Talon to extract new content from email replies, removing quoted text with 93.8% accuracy.
|
|
4900
|
+
|
|
4901
|
+
## Why Talon?
|
|
4902
|
+
|
|
4903
|
+
Email threads accumulate quoted replies that clutter the actual content. When processing emails programmatically, you need just the new message, not the entire conversation history.
|
|
4904
|
+
|
|
4905
|
+
**Talon solves this problem** by extracting clean reply content through sophisticated pattern matching and structural analysis.
|
|
4906
|
+
|
|
4907
|
+
### Use Cases
|
|
4908
|
+
|
|
4909
|
+
* **AI Email Agents**: Extract new user messages without processing entire thread history
|
|
4910
|
+
* **Email Automation**: Parse replies to identify actionable content
|
|
4911
|
+
* **Thread Analysis**: Build conversation flows by isolating individual contributions
|
|
4912
|
+
* **Inbox Management**: Process only new information from replies
|
|
4913
|
+
|
|
4914
|
+
### Why Choose Talon?
|
|
4915
|
+
|
|
4916
|
+
<CardGroup cols={2}>
|
|
4917
|
+
<Card title="HTML Email Support" icon="fa-regular fa-file-code">
|
|
4918
|
+
Handles Gmail, Outlook, Apple Mail, Thunderbird HTML structures
|
|
4919
|
+
</Card>
|
|
4920
|
+
|
|
4921
|
+
<Card title="High Accuracy" icon="fa-regular fa-bullseye">
|
|
4922
|
+
93.8% success rate across 64 real-world test cases
|
|
4923
|
+
</Card>
|
|
4924
|
+
|
|
4925
|
+
<Card title="Multi-language" icon="fa-regular fa-globe">
|
|
4926
|
+
Supports English, Japanese, Swedish, Polish, Dutch, German
|
|
4927
|
+
</Card>
|
|
4928
|
+
|
|
4929
|
+
<Card title="Fast Performance" icon="fa-regular fa-gauge-high">
|
|
4930
|
+
1.92ms average processing time, 488 emails/second
|
|
4931
|
+
</Card>
|
|
4932
|
+
</CardGroup>
|
|
4933
|
+
|
|
4934
|
+
***
|
|
4935
|
+
|
|
4936
|
+
## How Talon Works
|
|
4937
|
+
|
|
4938
|
+
Talon uses two complementary approaches depending on email format:
|
|
4939
|
+
|
|
4940
|
+
### Plain Text Processing (6-Stage Pipeline)
|
|
4941
|
+
|
|
4942
|
+
1. **Line Classification**: Assigns markers to each line ('t'=text, 'm'=quote marker, 's'=splitter, 'e'=empty)
|
|
4943
|
+
2. **Pattern Matching**: Applies regex to marker sequences to identify quoted blocks
|
|
4944
|
+
3. **Content Extraction**: Removes quoted lines and returns clean text
|
|
4945
|
+
|
|
4946
|
+
Recognizes patterns like:
|
|
4947
|
+
|
|
4948
|
+
* Standard quote markers (`>`)
|
|
4949
|
+
* Reply headers ("On \[date] \[name] wrote:")
|
|
4950
|
+
* Forward indicators ("-----Original Message-----")
|
|
4951
|
+
|
|
4952
|
+
### HTML Processing (8-Stage Pipeline)
|
|
4953
|
+
|
|
4954
|
+
1. **Structural Removal**: Directly removes known quotation elements (Gmail divs, blockquotes, Outlook markup)
|
|
4955
|
+
2. **Checkpoint Fallback**: For non-standard HTML, maps elements to text lines, applies text patterns, removes corresponding HTML
|
|
4956
|
+
|
|
4957
|
+
### Processing Systems
|
|
4958
|
+
|
|
4959
|
+
**Quotation Removal** (Primary)
|
|
4960
|
+
|
|
4961
|
+
* Removes quoted replies from thread
|
|
4962
|
+
* No initialization required
|
|
4963
|
+
* Rule-based pattern matching
|
|
4964
|
+
|
|
4965
|
+
***
|
|
4966
|
+
|
|
4967
|
+
## Getting Started
|
|
4968
|
+
|
|
4969
|
+
<Steps>
|
|
4970
|
+
<Step title="Install Talon">
|
|
4971
|
+
Install via pip with required workaround for Python 3.11+:
|
|
4972
|
+
|
|
4973
|
+
<CodeBlocks>
|
|
4974
|
+
```bash
|
|
4975
|
+
pip install talon
|
|
4976
|
+
```
|
|
4977
|
+
</CodeBlocks>
|
|
4978
|
+
</Step>
|
|
4979
|
+
|
|
4980
|
+
<Step title="Apply Python 3.11+ Workaround">
|
|
4981
|
+
Required fix for cchardet dependency:
|
|
4982
|
+
|
|
4983
|
+
<CodeBlocks>
|
|
4984
|
+
```python
|
|
4985
|
+
# Import workaround BEFORE importing talon
|
|
4986
|
+
import sys
|
|
4987
|
+
import chardet
|
|
4988
|
+
sys.modules['cchardet'] = chardet
|
|
4989
|
+
|
|
4990
|
+
# Now safe to import talon
|
|
4991
|
+
import talon
|
|
4992
|
+
from talon import quotations
|
|
4993
|
+
```
|
|
4994
|
+
</CodeBlocks>
|
|
4995
|
+
|
|
4996
|
+
<Callout intent="warn">
|
|
4997
|
+
This workaround is **required** for Python 3.11+.
|
|
4998
|
+
</Callout>
|
|
4999
|
+
</Step>
|
|
5000
|
+
|
|
5001
|
+
<Step title="Extract Reply Content">
|
|
5002
|
+
Basic usage for plain text and HTML:
|
|
5003
|
+
|
|
5004
|
+
<CodeBlocks>
|
|
5005
|
+
```python title="Plain Text"
|
|
5006
|
+
from talon import quotations
|
|
5007
|
+
|
|
5008
|
+
email = """Great work on the project!
|
|
5009
|
+
|
|
5010
|
+
On Mon, Apr 11, 2011 at 6:54 PM, Bob wrote:
|
|
5011
|
+
> Can you review the document?
|
|
5012
|
+
> Need feedback by Friday.
|
|
5013
|
+
"""
|
|
5014
|
+
|
|
5015
|
+
clean_reply = quotations.extract_from_plain(email)
|
|
5016
|
+
# Result: "Great work on the project!"
|
|
5017
|
+
```
|
|
5018
|
+
|
|
5019
|
+
```python title="HTML"
|
|
5020
|
+
from talon import quotations
|
|
5021
|
+
|
|
5022
|
+
html_email = """
|
|
5023
|
+
<html><body>
|
|
5024
|
+
<div>Thanks for the update!</div>
|
|
5025
|
+
<div class="gmail_quote">
|
|
5026
|
+
<div>On Mon, Alice wrote:</div>
|
|
5027
|
+
<blockquote>Original message here</blockquote>
|
|
5028
|
+
</div>
|
|
5029
|
+
</body></html>
|
|
5030
|
+
"""
|
|
5031
|
+
|
|
5032
|
+
clean_html = quotations.extract_from_html(html_email)
|
|
5033
|
+
# Returns: <html><body><div>Thanks for the update!</div></body></html>
|
|
5034
|
+
```
|
|
5035
|
+
</CodeBlocks>
|
|
5036
|
+
</Step>
|
|
5037
|
+
</Steps>
|
|
5038
|
+
|
|
5039
|
+
***
|
|
5040
|
+
|
|
5041
|
+
## Performance & Accuracy
|
|
5042
|
+
|
|
5043
|
+
Talon has been tested on 64 real-world emails from various clients and languages.
|
|
5044
|
+
|
|
5045
|
+
### Test Results Summary
|
|
5046
|
+
|
|
5047
|
+
| Metric | Value |
|
|
5048
|
+
| ----------------------- | ------------------- |
|
|
5049
|
+
| **Total Tests** | 64 emails |
|
|
5050
|
+
| **Passed** | 60 (93.8%) |
|
|
5051
|
+
| **Failed** | 4 (6.2%) |
|
|
5052
|
+
| **Avg Processing Time** | 1.92ms |
|
|
5053
|
+
| **Throughput** | 488.6 emails/second |
|
|
5054
|
+
| **Min/Max Time** | 0.13ms - 21.55ms |
|
|
5055
|
+
|
|
5056
|
+
### Test Coverage
|
|
5057
|
+
|
|
5058
|
+
* **22 HTML emails**: Gmail, Outlook, Apple Mail, Thunderbird, Mail.ru, Hotmail
|
|
5059
|
+
* **42 plain text emails**: Various formats and reply styles
|
|
5060
|
+
* **6+ languages**: English, Japanese, Swedish, Polish, Dutch, German
|
|
5061
|
+
* **Mobile clients**: iPhone, Android "Sent from" signatures
|
|
5062
|
+
|
|
5063
|
+
### Processing Time by Complexity
|
|
5064
|
+
|
|
5065
|
+
| Email Type | Avg Time | Complexity |
|
|
5066
|
+
| ------------------ | --------- | ---------- |
|
|
5067
|
+
| Simple text reply | 0.2-0.5ms | Low |
|
|
5068
|
+
| HTML Gmail/Outlook | 2-4ms | Medium |
|
|
5069
|
+
| Complex threads | 4-22ms | High |
|
|
5070
|
+
|
|
5071
|
+
### Speed vs Accuracy Tradeoff
|
|
5072
|
+
|
|
5073
|
+
| Library | Avg Processing Time | Accuracy | Best For |
|
|
5074
|
+
| ------------ | ------------------- | -------- | --------------------------------------- |
|
|
5075
|
+
| **Talon** | 1.92ms | 93.8% | Production systems needing HTML support |
|
|
5076
|
+
| qutoequail | 0.96ms | \~85% | Moderate accuracy requirements |
|
|
5077
|
+
| Custom regex | 0.1ms | \~70% | Simple plain text, speed critical |
|
|
5078
|
+
|
|
5079
|
+
**Insight**: For production systems, 1.92ms average is negligible. Even at worst case (21.55ms), Talon is faster than most network requests.
|
|
5080
|
+
|
|
5081
|
+
***
|
|
5082
|
+
|
|
5083
|
+
## Known Limitations
|
|
5084
|
+
|
|
5085
|
+
Talon failed 4 out of 64 test cases. Here's what didn't work:
|
|
5086
|
+
|
|
5087
|
+
<AccordionGroup>
|
|
5088
|
+
<Accordion title="Failed Test Cases (4 total)">
|
|
5089
|
+
### Test Case 1: Complex Email Thread with Mixed Content
|
|
5090
|
+
|
|
5091
|
+
**Input**:
|
|
5092
|
+
|
|
5093
|
+
```text
|
|
5094
|
+
Thank you, Sonya Johnson.
|
|
5095
|
+
|
|
5096
|
+
I have sent an invite for 10:30am Monday PDT (today). I
|
|
5097
|
+
hope you can join.
|
|
5098
|
+
|
|
5099
|
+
Regards,
|
|
5100
|
+
|
|
5101
|
+
Christopher Edwards
|
|
5102
|
+
|
|
5103
|
+
|
|
5104
|
+
On Mon, Jun 3, 2024 at 12:53 AM Cody Hart <omerritt@example.com> wrote:
|
|
5105
|
+
|
|
5106
|
+
> Hi Christopher Edwards,
|
|
5107
|
+
>
|
|
5108
|
+
> 10.30 AM pacific is good for me.
|
|
5109
|
+
>
|
|
5110
|
+
> Thanks & Regards,
|
|
5111
|
+
>
|
|
5112
|
+
> Cody Hart
|
|
5113
|
+
```
|
|
5114
|
+
|
|
5115
|
+
**Expected Output**: First 5 lines only (up to `Christopher Edwards`)
|
|
5116
|
+
|
|
5117
|
+
**Talon's Output**: Returns entire email including quoted text starting with "On Mon, Jun 3..." and all "> quoted text"
|
|
5118
|
+
|
|
5119
|
+
**Processing Time**: 2.55ms
|
|
5120
|
+
|
|
5121
|
+
**Issue**: Signature placement before quotes confuses detection logic
|
|
5122
|
+
|
|
5123
|
+
***
|
|
5124
|
+
|
|
5125
|
+
### Test Case 2: Inline Responses
|
|
5126
|
+
|
|
5127
|
+
**Input**:
|
|
5128
|
+
|
|
5129
|
+
```text
|
|
5130
|
+
On Tue, Apr 29, 2014 at 4:22 PM, Example Dev <sugar@example.com> wrote:
|
|
5131
|
+
|
|
5132
|
+
> okay. Well, here's some stuff I can write.
|
|
5133
|
+
>
|
|
5134
|
+
> And if I write a 2 second line you and maybe reply under this?
|
|
5135
|
+
>
|
|
5136
|
+
> Or if you didn't really feel like it, you could reply under this line.
|
|
5137
|
+
|
|
5138
|
+
I will reply under this one
|
|
5139
|
+
|
|
5140
|
+
>
|
|
5141
|
+
> okay?
|
|
5142
|
+
>
|
|
5143
|
+
|
|
5144
|
+
and under this.
|
|
5145
|
+
|
|
5146
|
+
>
|
|
5147
|
+
> -- Tim
|
|
5148
|
+
```
|
|
5149
|
+
|
|
5150
|
+
**Expected Output**: Just the inline responses (`I will reply under this one` and `and under this.`)
|
|
5151
|
+
|
|
5152
|
+
**Talon's Output**: Returns everything including "On Tue, Apr 29..." header and all quoted lines
|
|
5153
|
+
|
|
5154
|
+
**Processing Time**: 0.48ms
|
|
5155
|
+
|
|
5156
|
+
**Issue**: Interleaved inline responses not recognized as the reply pattern
|
|
5157
|
+
|
|
5158
|
+
***
|
|
5159
|
+
|
|
5160
|
+
### Test Case 3: Gmail Forward HTML
|
|
5161
|
+
|
|
5162
|
+
**Input**:
|
|
5163
|
+
|
|
5164
|
+
```html
|
|
5165
|
+
<html><head></head><body><div dir="ltr">test<div><br /></div><div>blah</div>
|
|
5166
|
+
<div><br /><div class="gmail_quote">---------- Forwarded message ----------<br />
|
|
5167
|
+
From: <b class="gmail_sendername">Foo Bar</b>
|
|
5168
|
+
<span dir="ltr"><<a href="mailto:foo@bar.example">foo@bar.example</a>></span><br />
|
|
5169
|
+
Date: Thu, Mar 24, 2016 at 5:17 PM<br />
|
|
5170
|
+
Subject: The Subject<br />
|
|
5171
|
+
To: John Doe <<a href="mailto:john@doe.example">john@doe.example</a>><br />
|
|
5172
|
+
<br /><br /><div dir="ltr">Some text<div><br /></div><div><br /></div></div>
|
|
5173
|
+
</div><br /></div></div></body></html>
|
|
5174
|
+
```
|
|
5175
|
+
|
|
5176
|
+
**Expected Output**: Just `testblah` (before the forward marker)
|
|
5177
|
+
|
|
5178
|
+
**Talon's Output**: Includes "---------- Forwarded message ----------" and forwarded content
|
|
5179
|
+
|
|
5180
|
+
**Processing Time**: 3.41ms
|
|
5181
|
+
|
|
5182
|
+
**Issue**: HTML forward headers not removed by Gmail quote detection
|
|
5183
|
+
|
|
5184
|
+
***
|
|
5185
|
+
|
|
5186
|
+
### Test Case 4: Thunderbird Forward HTML
|
|
5187
|
+
|
|
5188
|
+
**Input**:
|
|
5189
|
+
|
|
5190
|
+
```html
|
|
5191
|
+
<html><body bgcolor="#FFFFFF" text="#000000">
|
|
5192
|
+
<p><br /></p>
|
|
5193
|
+
<div class="moz-forward-container"><br /><br />
|
|
5194
|
+
-------- Forwarded Message --------
|
|
5195
|
+
<table class="moz-email-headers-table">
|
|
5196
|
+
<tbody>
|
|
5197
|
+
<tr><th>Subject:</th><td>Re: Example subject</td></tr>
|
|
5198
|
+
<tr><th>Date:</th><td>Tue, 3 May 2016 14:54:27 +0200 (CEST)</td></tr>
|
|
5199
|
+
<tr><th>From:</th><td>John Doe <johndoe@example.com></td></tr>
|
|
5200
|
+
</tbody>
|
|
5201
|
+
</table>
|
|
5202
|
+
<br /><br />
|
|
5203
|
+
<div>Dear John,</div>
|
|
5204
|
+
<div><br /></div>
|
|
5205
|
+
<div>This is a test.</div>
|
|
5206
|
+
</div></body></html>
|
|
5207
|
+
```
|
|
5208
|
+
|
|
5209
|
+
**Expected Output**: Empty (no new content, just forward)
|
|
5210
|
+
|
|
5211
|
+
**Talon's Output**: Includes "-------- Forwarded Message --------" and forwarded content
|
|
5212
|
+
|
|
5213
|
+
**Processing Time**: 4.34ms
|
|
5214
|
+
|
|
5215
|
+
**Issue**: Thunderbird's `moz-forward-container` class not recognized
|
|
5216
|
+
|
|
5217
|
+
***
|
|
5218
|
+
|
|
5219
|
+
**Summary**: 3 of 4 failures are forwarded messages. Regular replies work with 98%+ accuracy.
|
|
5220
|
+
</Accordion>
|
|
5221
|
+
|
|
5222
|
+
<Accordion title="Success Examples">
|
|
5223
|
+
### Example 1: Simple Gmail Reply
|
|
5224
|
+
|
|
5225
|
+
**Input**:
|
|
5226
|
+
|
|
5227
|
+
```text
|
|
5228
|
+
Awesome! I haven't had another problem with it.
|
|
5229
|
+
|
|
5230
|
+
On Aug 22, 2011, at 7:37 PM, defunkt<reply@reply.github.com> wrote:
|
|
5231
|
+
|
|
5232
|
+
|
|
5233
|
+
|
|
5234
|
+
|
|
5235
|
+
> Loader seems to be working well.
|
|
5236
|
+
```
|
|
5237
|
+
|
|
5238
|
+
**Talon's Output**: `Awesome! I haven't had another problem with it.`
|
|
5239
|
+
|
|
5240
|
+
**Processing Time**: 0.2ms
|
|
5241
|
+
|
|
5242
|
+
**What Worked**: Standard "On \[date] \[name] wrote:" pattern detected, quote marker (>) recognized
|
|
5243
|
+
|
|
5244
|
+
***
|
|
5245
|
+
|
|
5246
|
+
### Example 2: Outlook Reply with Separator
|
|
5247
|
+
|
|
5248
|
+
**Input**:
|
|
5249
|
+
|
|
5250
|
+
```text
|
|
5251
|
+
Outlook with a reply directly above line
|
|
5252
|
+
________________________________________
|
|
5253
|
+
From: CRM Comments [crm-comment@example.com]
|
|
5254
|
+
Sent: Friday, 23 March 2012 5:08 p.m.
|
|
5255
|
+
To: John S. Greene
|
|
5256
|
+
Subject: [contact:106] John Greene
|
|
5257
|
+
|
|
5258
|
+
A new comment has been added to the Contact named 'John Greene':
|
|
5259
|
+
|
|
5260
|
+
I am replying to a comment.
|
|
5261
|
+
```
|
|
5262
|
+
|
|
5263
|
+
**Talon's Output**: `Outlook with a reply directly above line`
|
|
5264
|
+
|
|
5265
|
+
**Processing Time**: 0.51ms
|
|
5266
|
+
|
|
5267
|
+
**What Worked**: Outlook separator line (underscores) and "From:"/"Sent:" headers detected as splitter
|
|
5268
|
+
|
|
5269
|
+
***
|
|
5270
|
+
|
|
5271
|
+
### Example 3: HTML Outlook Reply
|
|
5272
|
+
|
|
5273
|
+
**Input**:
|
|
5274
|
+
|
|
5275
|
+
```html
|
|
5276
|
+
<html>
|
|
5277
|
+
<body>
|
|
5278
|
+
<div>Reply</div>
|
|
5279
|
+
<span id="OLK_SRC_BODY_SECTION">
|
|
5280
|
+
<div>
|
|
5281
|
+
<span>From: </span>Bob <<a href="mailto:bob@example.com">bob@example.com</a>><br />
|
|
5282
|
+
<span>Date: </span>Tue, 01 Nov 2011 18:54:39 -0700<br />
|
|
5283
|
+
<span>To: </span>Rob <<a href="mailto:rob@example.com">rob@example.com</a>><br />
|
|
5284
|
+
<span>Subject: </span>Test<br />
|
|
5285
|
+
</div>
|
|
5286
|
+
<div>Hi</div>
|
|
5287
|
+
</span>
|
|
5288
|
+
</body>
|
|
5289
|
+
</html>
|
|
5290
|
+
```
|
|
5291
|
+
|
|
5292
|
+
**Talon's Output**: `Reply`
|
|
5293
|
+
|
|
5294
|
+
**Processing Time**: 4.02ms
|
|
5295
|
+
|
|
5296
|
+
**What Worked**: Outlook's `OLK_SRC_BODY_SECTION` span ID detected and removed structurally
|
|
5297
|
+
</Accordion>
|
|
5298
|
+
|
|
5299
|
+
<Accordion title="Performance vs Simpler Alternatives">
|
|
5300
|
+
**Tradeoff**: Talon is more comprehensive but slower than plain-text-only libraries
|
|
5301
|
+
|
|
5302
|
+
* Talon: 1.92ms average (with HTML support)
|
|
5303
|
+
* email-reply-parser: 0.03ms average (plain text only)
|
|
5304
|
+
|
|
5305
|
+
For production systems, 1.92ms average is negligible. Even at worst case (21.55ms), Talon is faster than most network requests.
|
|
5306
|
+
</Accordion>
|
|
5307
|
+
|
|
5308
|
+
<Accordion title="Forwarded Messages">
|
|
5309
|
+
As shown in test results, forwarded messages (especially HTML) are challenging:
|
|
5310
|
+
|
|
5311
|
+
* Plain text forwards: Generally work well
|
|
5312
|
+
* HTML forwards: May retain forward headers
|
|
5313
|
+
* Workaround: Use plain text extraction or post-process to remove forward markers
|
|
5314
|
+
</Accordion>
|
|
5315
|
+
</AccordionGroup>
|
|
5316
|
+
|
|
5317
|
+
***
|
|
5318
|
+
|
|
5319
|
+
### Error Handling
|
|
5320
|
+
|
|
5321
|
+
Always handle potential parsing failures:
|
|
5322
|
+
|
|
5323
|
+
```python
|
|
5324
|
+
from talon import quotations
|
|
5325
|
+
|
|
5326
|
+
def safe_extract(email_body, is_html=False):
|
|
5327
|
+
try:
|
|
5328
|
+
if is_html:
|
|
5329
|
+
return quotations.extract_from_html(email_body)
|
|
5330
|
+
else:
|
|
5331
|
+
return quotations.extract_from_plain(email_body)
|
|
5332
|
+
except Exception as e:
|
|
5333
|
+
# Fallback to original message if extraction fails
|
|
5334
|
+
print(f"Talon extraction failed: {e}")
|
|
5335
|
+
return email_body
|
|
5336
|
+
```
|
|
5337
|
+
|
|
5338
|
+
### Testing Recommendations
|
|
5339
|
+
|
|
5340
|
+
Always test with your specific email formats:
|
|
5341
|
+
|
|
5342
|
+
```python
|
|
5343
|
+
# Create a test suite with your actual email patterns (Gmail, Outlook, Apple Mail)
|
|
5344
|
+
test_emails = [
|
|
5345
|
+
"path/to/gmail_reply.html",
|
|
5346
|
+
"path/to/outlook_reply.txt",
|
|
5347
|
+
"path/to/forward.html"
|
|
5348
|
+
]
|
|
5349
|
+
|
|
5350
|
+
for email_file in test_emails:
|
|
5351
|
+
with open(email_file) as f:
|
|
5352
|
+
content = f.read()
|
|
5353
|
+
result = quotations.extract_from(content)
|
|
5354
|
+
print(f"{email_file}: {len(result)} chars extracted")
|
|
5355
|
+
```
|
|
5356
|
+
|
|
5357
|
+
<Tip>
|
|
5358
|
+
Test with real emails from your users' actual email clients. Talon's accuracy is based on diverse real-world samples, but your specific use case may have unique patterns.
|
|
5359
|
+
</Tip>
|
|
5360
|
+
|
|
5361
|
+
***
|
|
5362
|
+
|
|
5363
|
+
## JavaScript Version
|
|
5364
|
+
|
|
5365
|
+
For TypeScript/JavaScript projects, use **[TalonJS](https://github.com/quentez/talonjs)** - a JavaScript port of Talon with similar functionality.
|
|
5366
|
+
|
|
5367
|
+
### Performance Comparison
|
|
5368
|
+
|
|
5369
|
+
| Solution | Accuracy | Speed | Best For |
|
|
5370
|
+
| ---------------- | -------- | ------ | --------------------------- |
|
|
5371
|
+
| **Python Talon** | 93.8% | 1.92ms | Highest accuracy |
|
|
5372
|
+
| **TalonJS** | 90.6% | 1.88ms | TypeScript/Node.js projects |
|
|
5373
|
+
|
|
5374
|
+
TalonJS provides 90.6% accuracy with slightly faster performance (1.88ms), making it ideal for JavaScript/TypeScript environments without needing Python dependencies.
|
|
5375
|
+
|
|
5376
|
+
### Quick Start
|
|
5377
|
+
|
|
5378
|
+
<Steps>
|
|
5379
|
+
<Step title="Install TalonJS">
|
|
5380
|
+
```bash
|
|
5381
|
+
npm install talonjs
|
|
5382
|
+
```
|
|
5383
|
+
</Step>
|
|
5384
|
+
|
|
5385
|
+
<Step title="Extract Replies">
|
|
5386
|
+
<CodeBlocks>
|
|
5387
|
+
```typescript title="Plain Text"
|
|
5388
|
+
import * as talon from 'talonjs';
|
|
5389
|
+
|
|
5390
|
+
const email = `Great work on the project!
|
|
5391
|
+
|
|
5392
|
+
On Mon, Apr 11, 2011 at 6:54 PM, Bob wrote:
|
|
5393
|
+
> Can you review the document?
|
|
5394
|
+
> Need feedback by Friday.
|
|
5395
|
+
`;
|
|
5396
|
+
|
|
5397
|
+
const result = talon.quotations.extractFromPlain(email);
|
|
5398
|
+
const cleanReply = result.body.trim();
|
|
5399
|
+
// Output: "Great work on the project!"
|
|
5400
|
+
```
|
|
5401
|
+
|
|
5402
|
+
```typescript title="HTML"
|
|
5403
|
+
import * as talon from 'talonjs';
|
|
5404
|
+
|
|
5405
|
+
const htmlEmail = `
|
|
5406
|
+
<div>Thanks for the update!</div>
|
|
5407
|
+
<div class="gmail_quote">
|
|
5408
|
+
On Mon, Alice wrote: <blockquote>Original</blockquote>
|
|
5409
|
+
</div>
|
|
5410
|
+
`;
|
|
5411
|
+
|
|
5412
|
+
const result = talon.quotations.extractFromHtml(htmlEmail);
|
|
5413
|
+
const cleanReply = result.body.trim();
|
|
5414
|
+
// Returns: "<div>Thanks for the update!</div>"
|
|
5415
|
+
// Note: TalonJS returns clean HTML, not plain text
|
|
5416
|
+
```
|
|
5417
|
+
</CodeBlocks>
|
|
5418
|
+
</Step>
|
|
5419
|
+
</Steps>
|
|
5420
|
+
|
|
5421
|
+
<Tip>
|
|
5422
|
+
**When to use TalonJS vs Python Talon:**
|
|
5423
|
+
|
|
5424
|
+
* Use **TalonJS** if you're building in TypeScript/JavaScript and 90.6% accuracy is sufficient
|
|
5425
|
+
* Use **Python Talon** if you need the highest accuracy (93.8%) or are in a Python environment
|
|
5426
|
+
* The 3.2% accuracy difference is acceptable for most use cases
|
|
5427
|
+
</Tip>
|
|
5428
|
+
|
|
5429
|
+
|
|
4878
5430
|
# Join the AgentMail Community
|
|
4879
5431
|
|
|
4880
5432
|
> Connect with the AgentMail team and developers, share what you're building, and get support.
|
|
4881
5433
|
|
|
4882
5434
|
<CardGroup>
|
|
4883
|
-
<Card title="Join our Discord Server" href="https://discord.
|
|
5435
|
+
<Card title="Join our Discord Server" href="https://discord.com/invite/hTYatWYWBc" icon="fa-brands fa-discord">
|
|
4884
5436
|
The best place for real-time conversation, getting help with your code, and
|
|
4885
5437
|
sharing what you're building with AgentMail.
|
|
4886
5438
|
</Card>
|