AI 资讯
Build a webhook-driven email pipeline for your AI agent
Most "AI email" tutorials end with a while True loop that polls an inbox every thirty seconds, runs the new messages through a model, and sends a reply. It demos fine. Then you put it in front of real traffic and the cracks show up immediately: you're burning API calls to fetch nothing 99% of the time, your reaction latency is bounded by your poll interval, and the moment you scale to more than one inbox the polling cost multiplies. Polling an agent's inbox is wasteful. Webhooks are the right primitive for this. The mailbox already knows the instant a message lands — there's no reason to keep asking. What you actually want is a pipeline: inbound mail fans out to a verified ingest endpoint, lands on a queue, and gets picked up by workers that drive your agent runtime and send the reply. This post is about that architecture end to end — not a single feature, but the whole flow, with the parts that bite you in production (idempotency, retries, ordering, backpressure) called out honestly. I work on the Nylas CLI, so the terminal commands below are the exact ones I reach for when I'm wiring this up. I'll show the curl HTTP call and the CLI equivalent for every concrete step, because you'll use both: curl in your provisioning scripts, the CLI when you're poking at a live account. The mental model: an Agent Account is just a grant Before any of the pipeline matters, here's the one abstraction that makes the whole thing simple. An Agent Account is a Nylas grant — it has a grant_id , an inbox, an email address on a domain you own, and it speaks every grant-scoped endpoint you already know: Messages, Threads, Folders, Drafts, Attachments, Calendars, Events, Contacts, Webhooks. There's no OAuth token to refresh, no provider-specific quirks, no separate SDK. If you've built against a connected Gmail or Microsoft grant before, the data plane is identical. Nothing new to learn there. What's different is that the agent is a participant. It has its own address — support@yourcompany
AI 资讯
Make your email agent idempotent against duplicate webhooks
Most posts about "AI email agents" stop at the happy path: webhook fires, model drafts a reply, agent sends it. Demo works, screenshot looks great, ship it. Then it goes to production and the agent replies to the same customer twice ninety seconds apart, and now your "intelligent assistant" looks like a broken cron job. That second reply isn't a bug in your model. It's a property of the delivery system, and it's guaranteed to happen eventually. Nylas webhooks are at-least-once: the same event can arrive up to three times. If your handler treats every POST as a fresh event, every retry is a second action. For a logging pipeline that's harmless. For an agent that sends email on your behalf , a duplicate delivery is a duplicate reply, and a double-reply embarrasses the agent in front of the exact person you built it to impress. So this post is about the engineering of idempotency itself, applied to an Agent Account. Not "remember to dedupe" hand-waving — the actual moving parts: which field is the real dedup key, how to persist processed ids atomically, why you ack before you work, how to make the send path itself idempotent, and where a per-thread lock catches the race that dedup alone can't. I work on the Nylas CLI, so every terminal command below is one I've actually run, verified against nylas v3.1.27. What an Agent Account changes (and what it doesn't) An Agent Account is just a grant. It has a grant_id and works with every grant-scoped endpoint — Messages, Drafts, Threads, Folders — exactly like a connected Gmail or Microsoft account. The difference is it's an inbox the agent owns : support@yourcompany.com is the agent, not a human whose inbox the agent borrows. Inbound mail to that address fires the standard message.created webhook, the agent reads it, and the agent replies from its own address. Nothing new to learn on the data plane. That's the whole point of the grant abstraction — the idempotency work below is plain webhook-handling discipline, and it transfe
AI 资讯
Connect legacy tools to an agent mailbox over IMAP/SMTP
Most "AI email" integrations assume everything on the other side speaks REST. You wire up a webhook, you call POST /messages/send , and you move on. That works right up until you remember how much of your stack doesn't speak REST and never will: the ticketing system that ingests mail over IMAP, the backup script your predecessor wrote in 2014, the monitoring tool that only knows how to send SMTP, the compliance archiver that polls a mailbox every five minutes. None of those are getting rewritten to call an HTTP API for your demo. So here's the trick that makes a Nylas Agent Account genuinely useful in a real environment: it's not API-only. You can expose the same mailbox over IMAP and SMTP submission , hand the host, port, and credentials to one of those legacy tools, and let it read and send like it's talking to any old mail server. Meanwhile your agent drives that identical mailbox over the v3 API. Both surfaces hit one storage layer. A flag, move, or delete on either side shows up on the other within seconds. I work on the Nylas CLI, so the terminal commands below are the exact ones I reach for. As usual I'll show both angles for every operation — the raw curl against the API and the nylas command — because half the point of an Agent Account is that you can mix them freely. What you actually get An Agent Account is just a grant . It has a grant_id , and that grant_id works with every grant-scoped endpoint you already know — Messages, Drafts, Threads, Folders, Attachments, Contacts, Calendars, Events. There's nothing new to learn on the data plane. The IMAP/SMTP layer doesn't change that model. It adds a second door into the same room: One mailbox, two protocols. The API and the IMAP/SMTP server are two front-ends over the same backend. There is no sync job, no eventual-consistency window worth worrying about, no "API mailbox" versus "client mailbox." It's one mailbox. Legacy tools just work. Anything that can authenticate to an IMAP server with a username and pas
AI 资讯
Agility Robotics plants its flag in Tesla’s backyard
Agility is opening a new training center for its Digit robots in Fremont, California.
产品设计
Shark’s versatile ChillPill cooling system is back to its best price
Portable fans are one of the easiest ways to stay cool during the summer, and you don’t have to spend much to find a decent one. If you’re looking for something more versatile, though, Shark’s ChillPill Personal Fan and Cooling System combines a rechargeable fan with a dry-touch evaporative mister in a design that can […]
AI 资讯
AI-driven memory crunch jolts India’s smartphone market
India's smartphone slowdown highlights how the AI boom is reshaping consumer electronics, from pricing and demand to corporate strategy.
开发者
Seed7 version 2026-07-11 released
Seed7 is a GPL licensed open source programming language. It is given away for free and nobody from the development team gets any money from it. submitted by /u/ThomasMertes [link] [留言]
AI 资讯
Maintaining the code of the man who wrote "How To Write Unmaintainable Code"
Today I accidentally became the maintainer of software that was already almost three decades old: reviving a 1990s Java utility to keep the last PAD submitter alive in 2026. I was looking for a way to submit my AI app RiverScript to old desktop software directories and ended up digging through the long-forgotten world of PAD files. There was one problem. The only batch submission tool I could find was a Java application that first appeared in the late 1990s. The last release was in 2017. It was written by Roedy Green of Canadian Mind Products — a software developer who passed away in 2023. He spent decades writing and freely distributing Java utilities, and maintaining the widely-read Java Glossary . Roedy Green also wrote How To Write Unmaintainable Code — a famous satirical guide about writing code nobody can maintain. So, Roedy, today the code you wrote almost three decades ago was maintained. The tool still did exactly what it was supposed to do. Thank you. It just had absolutely no idea the modern web existed. It happily produced URLs like http://https://riverscript.com instead of https://riverscript.com , disabled SNI globally (which was probably a perfectly reasonable workaround at some point), and couldn't cope with the fact that almost every website now redirects HTTP to HTTPS. So I dug through the legacy Java code, fixed the compatibility issues, and got it working again. I used it to submit my app to several software directories, then published the revived version on GitHub so anyone who still needs it can use it too. Maybe nobody will ever need it again. Maybe someone will. Either way, I'm happy this old thing works again. So today, the code of the man who wrote "How To Write Unmaintainable Code" is still being maintained even after he was gone. P.S. The public repository for Mini PAD Submitter 26.3 Revived — 2026 Community Fix is available and open to everyone. submitted by /u/Odd-Flamingo-6211 [link] [留言]
开发者
Google-backed satellites for wildfire detection launch as smoke chokes US, Canada
The FireSat program can spot wildfires that other satellites miss.
AI 资讯
Apple and Google ordered to purge ‘nudify’ apps from App Stores
In letters sent to Apple and Google, San Francisco City Attorney David Chiu said that both companies have long been aware that they are hosting apps in violation of state law.
开发者
Making TLA+ and x86 Kiss Via Z3Py
submitted by /u/mttd [link] [留言]
AI 资讯
Nuclear startup Valar Atomics in talks to raise new funding at $6B valuation
The potential deal highlights a growing trend of complex, multi-stage funding rounds that mask true entry prices.
开发者
The Pentagon's Space Development Agency hasn't moved as fast as anyone would like
"Missiles are being launched at the joint force every single day in [Operation] Epic Fury."
AI 资讯
What Cities From Chicago to Washington, DC, Look Like Under a Blanket of Wildfire Smoke
The US is home to some of the most polluted air on the planet as smoke from 120 out-of-control Canadian wildfires drifts across the border.
科技前沿
Zoox issues software recall because its robotaxis may be confused by smoke
The NHTSA recently called for autonomous vehicle companies to improve how cars respond in emergency situations.
AI 资讯
Installing Apache Kafka 4.2 on Ubuntu (WSL2): A Complete KRaft Step-by-Step Guide
Installing Apache Kafka 4.2 on Ubuntu 24.04 (WSL2) Using KRaft Mode: A Complete Step-by-Step Guide Learn how to install Apache Kafka 4.2 in KRaft mode, understand its architecture, create topics, produce and consume messages, and troubleshoot common configuration issues—all without ZooKeeper. 🚀 Introduction Apache Kafka has become the de facto standard for building event-driven , real-time , and high-throughput applications. Whether you're processing millions of financial transactions, collecting application logs, streaming IoT sensor data, or connecting microservices, Kafka provides a scalable and reliable messaging platform. Until recently, setting up Kafka required running Apache ZooKeeper alongside Kafka brokers. While powerful, ZooKeeper added operational complexity and introduced another distributed system that administrators had to manage. Beginning with recent Kafka releases, KRaft (Kafka Raft Metadata mode) removes this dependency by allowing Kafka to manage its own metadata internally. This makes installation simpler, reduces operational overhead, and improves scalability. In this guide, we'll install Apache Kafka 4.2 on Ubuntu 24.04.4 LTS (WSL2) , configure a single-node KRaft cluster, and walk through the complete lifecycle: Installing Kafka Understanding the Kafka architecture Configuring KRaft mode Starting the broker Creating topics Producing and consuming messages Troubleshooting common issues Understanding the purpose of each configuration parameter Rather than simply listing commands, I'll explain why each step is necessary so that you understand how Kafka works under the hood. What is Apache Kafka? Apache Kafka is a distributed event streaming platform designed to move data reliably and efficiently between applications. Instead of applications communicating directly with each other, they communicate through Kafka. A producing application writes messages to Kafka. Kafka stores those messages reliably. One or more consuming applications read those m
科技前沿
Hegseth wants a "High-T" military; doctors call it a clinical minefield
"We're turning the clock back on rational healthcare."
AI 资讯
Polling, SSE, or WebSockets for Mobile Upload Status?
After the browser transfers a file, the server may still scan, transcode, extract metadata, or generate previews. The interface needs status updates, but the most fashionable real-time transport is not automatically the most reliable choice for an event guest on a mobile browser. Start with the update contract Define states and transitions before choosing transport: accepted -> queued -> processing -> ready accepted -> rejected processing -> processing_error Every status response should include a monotonically increasing version or timestamp. The client can ignore events older than the state it already knows. Polling is a strong baseline HTTP polling works through proxies, resumes naturally after a page wake, and is easy to cache and rate-limit. Use adaptive intervals: one second just after acceptance, then back off to several seconds when processing takes longer. const delay = Math . min ( 8000 , 1000 * 2 ** slowChecks ); Add jitter when many guests finish at the same time. Stop when the state is terminal, the page is gone, or a server-provided retry time says to wait longer. SSE fits one-way progress Server-Sent Events are attractive when the server only pushes status. The browser reconnects with a last-event ID, and the wire format is simple. But mobile networks and some intermediaries silently kill idle connections. Send occasional heartbeats and treat reconnection as normal. The reconnect handler must fetch current state because events may have been missed beyond the server replay window. Do not keep one SSE stream per file. Subscribe by guest session or album and filter authorized upload IDs on the server. WebSockets add more responsibility WebSockets make sense when the client also sends frequent commands over the same channel or when a host moderation console needs many rapid updates. For a guest waiting on two files, they add connection authentication, heartbeat, reconnect, replay, and load-balancer complexity without much user benefit. Never rely on the so
AI 资讯
Impact of deployment topology on rate-limiting and trust proxy
The trust proxy setting is an important concept in backend development, especially when implementing rate-limiting in our APIs. But deciding its accurate value depends heavily on our deployment topology. When we deploy our application in production, the client may not talk directly to our backend. There may be 1 or more proxies in between who forward the request to the next proxy or the backend server. Those proxies can be Load balancers, API gateways, reverse proxy like nginx or any custom service. So effectively, our request has to do some 'hops' over these proxies to reach backend. When we implement rate limiting in app to prevent the DOS attack, we generally intend this rate limit on the basis of client IP address. And this works fine when client request reaches our backend directly. But when we have multi-hop architecture, the simple setup won't work as expected. Because the most recent IP will be of the proxy and not the client. So all the traffic coming from different users will be considered from the single client(our own proxy) and thus there will be false positives as the rate limiting will trigger much often. In this scenario, we must tell our backend to ignore these extra hops(i.e. to trust our proxies). This is done by specifying trust proxy. If there is 1 proxy between client-server we set trust proxy to 1; if there are 2, or more, we set it accordingly. This will ensure our express app skips(trusts) these IPs, and accurately figures out actual client IP. The originating IP address of client is identified from 'X-Forwarded-For' header by the express app. But setting trust proxy is not that straightforward. The numerical value for trust proxy will not work in every case. If there are different paths from which our request reaches backend, there is a chance that the number of proxies may be different in each path. For example - internal vs external traffic: External(public) traffic: (Client -> Web Application Firewall -> Load balancer -> Reverse Proxy ->
AI 资讯
Designing Upload Expiration as a Recoverable State
Signed upload sessions expire. Event contribution windows close. Storage reservations are reclaimed. These are normal lifecycle events, but many interfaces reduce all of them to “Upload failed.” A better protocol makes expiration explicit and recoverable where policy allows it. Distinguish three clocks An upload workflow usually has at least three deadlines: the event contribution window; the server-side upload intent expiry; the short-lived storage credential expiry. They should not share one timestamp. The event may accept contributions until midnight while a credential lasts five minutes and an intent can be renewed for an hour. Return the clocks in the session response with server time: { "serverNow" : "2026-07-17T18:00:00Z" , "eventClosesAt" : "2026-07-18T00:00:00Z" , "intentExpiresAt" : "2026-07-17T19:00:00Z" , "credentialExpiresAt" : "2026-07-17T18:05:00Z" } The client can display useful warnings without trusting its own clock for authorization. Model expiration by state A credential expiring during transfer is different from an intent expiring before completion. Use stable reasons: credential_expired -> request renewal intent_expired -> reconcile committed parts, then renew or restart event_closed -> stop new work, preserve local recovery guidance Do not automatically restart from byte zero. First ask the control plane which parts were committed and whether the original object key remains valid. Renew narrowly A renewal endpoint should accept the upload ID and prove continuity with the guest session. It rechecks event state, file policy, rate limits, and committed size. The response returns a new credential for the same object. Do not let the browser extend an intent indefinitely. Define a maximum session age and a bounded number of renewals. Long uploads may receive a larger initial policy based on file size and observed throughput. Handle the closing boundary fairly Decide what happens to an upload already transferring when the event window closes. Reasona