## Problem
`src/providers/emailsink.ts:18` calls `fetch(url)` with no abort signal or timeout. If the emailsink API is slow or unreachable:
- The `fetch` promise never settles — the test hangs indefinitely.
- The retry loop in `extractEmailContent` (`src/email.ts:81-95`) never activates because the error is never thrown.
- The test eventually times out via the test runner's global timeout, but the hang can last several minutes before that fires.
The codebase already uses `AbortSignal.timeout()` for this pattern in `src/index.ts:314` and `:517`.
## Steps to reproduce
1. Configure passmark with the emailsink provider.
2. Point DNS to a non-existent server or block the emailsink API.
3. Call `extractEmailContent()` — it hangs for the full runner timeout.
## Suggested fix
Add a timeout to the fetch call:
```ts
const response = await fetch(url, {
signal: AbortSignal.timeout(EMAIL_FETCH_TIMEOUT),
});
Add EMAIL_FETCH_TIMEOUT = 30000 to src/constants.ts. The AbortError propagates up and is gracefully caught by the existing try/catch in extractEmailContent.
Labels:
bug,medium-priority