Nodemailer HTTP Fetcher
nodemailer-fetch is a focused utility library designed to efficiently fetch HTTP URL contents. While primarily created to complement the Nodemailer ecosystem by providing a mechanism to retrieve remote content for email templates or attachments, it serves as a standalone HTTP client for general-purpose requests. The current stable version is 2.1.0. It generally follows a stable, on-demand release cadence typical for a mature utility module. Its key differentiators include robust handling of redirects (up to 5 by default), automatic gzip decompression, comprehensive cookie management with domain specificity, and built-in support for basic authentication, though with a notable caveat regarding redirects. It offers configurable TLS options and allows for custom HTTP methods (GET, POST), headers, and request bodies, making it flexible for various data fetching scenarios.
Common errors
-
Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported. Instead change the require of ... to a dynamic import()
cause Attempting to use `import` syntax (ES Modules) with `nodemailer-fetch`, which is a CommonJS module.fixChange your import statement from `import fetch from 'nodemailer-fetch';` to `const fetch = require('nodemailer-fetch');`. If your project is ESM-only, you might need to use dynamic `import('nodemailer-fetch')` or reconfigure your build system to handle CJS modules. -
Error: ETIMEDOUT
cause The HTTP request timed out before a response was received. This could be due to network issues, a slow server, or an overly aggressive timeout setting.fixIncrease the `timeout` option value (in milliseconds) if the server typically takes longer to respond, or check network connectivity and firewall settings between your application and the target server. -
Error: HTTP Error: 4xx (or 5xx)
cause The remote server responded with a non-2xx status code (e.g., 404 Not Found, 500 Internal Server Error) and `allowErrorResponse` option was not set to `true`.fixIf you expect and need to process non-successful HTTP responses, set the `allowErrorResponse: true` option in your fetch call. Otherwise, ensure the target URL and server logic are correct.
Warnings
- gotcha Basic authentication credentials are lost after the first HTTP redirect. If your target URL involves redirects and requires basic auth, the authentication will not be re-sent to the redirected location.
- gotcha Cookies are domain-specific and are not passed to different domains during redirects. Additionally, HTTPS-only cookies will not be sent to HTTP URLs, even within the same domain.
- gotcha By default, `nodemailer-fetch` allows invalid SSL certificates. This can pose a security risk in production environments as it disables critical security checks.
Install
-
npm install nodemailer-fetch -
yarn add nodemailer-fetch -
pnpm add nodemailer-fetch
Imports
- fetch
import fetch from 'nodemailer-fetch';
const fetch = require('nodemailer-fetch');
Quickstart
const fetch = require('nodemailer-fetch');
// Example 1: Basic GET request and pipe response to stdout
console.log('Fetching a public URL and piping response to stdout...');
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => {
if (!response || response.statusCode >= 400) {
throw new Error(`HTTP Error: ${response ? response.statusCode : 'No response'}`);
}
console.log(`
Status Code: ${response.statusCode}`);
console.log('Headers:', response.headers);
console.log('Body:');
return response;
})
.then(response => {
response.pipe(process.stdout);
response.on('end', () => console.log('\n--- Basic GET fetch complete ---'));
})
.catch(error => console.error('Error during basic GET fetch:', error.message));
// Example 2: POST request with custom body, headers, and timeout
console.log('\nSending a POST request with custom options...');
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: {
title: 'foo',
body: 'bar',
userId: 1
},
contentType: 'application/json', // Override default x-www-form-urlencoded
headers: {
'Accept': 'application/json',
'User-Agent': 'NodemailerFetchDemo/1.0'
},
timeout: 5000, // 5 seconds timeout for the connection
allowErrorResponse: true // Process response even if status code is non-2xx
})
.then(response => {
if (!response) {
throw new Error('No response received for POST request');
}
console.log(`
POST Status Code: ${response.statusCode}`);
return new Promise((resolve, reject) => {
let data = '';
response.on('data', chunk => data += chunk);
response.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (e) {
reject(new Error(`Failed to parse JSON response: ${data.substring(0, 100)}...`));
}
});
response.on('error', reject);
});
})
.then(json => {
console.log('POST Response Body:', json);
console.log('--- Custom POST fetch complete ---');
})
.catch(error => console.error('Error during custom POST fetch:', error.message));