Jak Wyślij e-mail przez API w JavaScript (Samouczek Node.js)
Pomiń standardowe teksty SMTP. Ten przewodnik pokazuje, jak wysyłać e-maile w Node.js za pomocą Unipile ujednolicone API poczty e-mail z kodem do kopiowania i wklejania dla Gmail, Outlook i SMTP w mniej niż 10 linijkach JavaScript.
import { UnipileClient } z 'unipile-node-sdk';
const klient = nowy UnipileClientprocess.env.UNIPILE_DSN,
process.env.UNIPILE_TOKEN
);
czekać client.email.wysyłać({
account_id: 'IDENTYFIKATOR_TWOJEGO_KONTA',
do: [{ display_name: 'Alicja',
identyfikator: 'alice@example.com' }],
temat: 'Cześć z Node.js',
body: 'Wysłano przez Unipile!
'
});5-wierszowy przykład Node.js
Jeśli już wiesz, czym jest API wysyłania wiadomości e-mail i i po prostu chcę wysłać kod API JavaScript do obsługi poczty e-mail, który faktycznie działa, oto on. Pełny tutorial znajduje się poniżej.
npm install unipile-node-sdkUNIPILE_DSN oraz UNIPILE_TOKEN do twojego .env plik.client.email.send()account_id, do, podmiotoraz ciało. Zrobione.import { UnipileClient } z 'unipile-node-sdk';
const klient = nowy UnipileClientprocess.env.UNIPILE_DSN,
process.env.UNIPILE_TOKEN
);
const wynik = await client.email.wysyłać({
account_id: 'acc_xxxxxxxxxxxxxxxx',
do: [{
nazwa_wyswietlana: 'Alicja Martin',
identyfikator: 'alice@acme.com'
}],
temat: 'Cześć z Node.js',
body: 'Wysłano przez API Unipile!
'
});
konsola.log(wynik); // { tracking_id: 'msg_...' }Wymagania wstępne i konfiguracja
Zanim będziesz mógł użyć przepływu pracy JavaScript API wysyłania wiadomości e-mail w produkcji, potrzebujesz czterech rzeczy: obsługiwanej wersji Node.js, pakietu SDK Unipile, klucza API i punktu końcowego DSN.
fetch i najwyższego poziomu czekać. Node 20 LTS jest zalecany do produkcji. Sprawdź swoją wersję za pomocą node -v.api4.unipile.com:13444Oba są wymagane do zainicjowania klienta..mjs pliki lub ustaw "typ":"moduł" w package.json. Dla CommonJS, dynamiczne import() działa również – przykłady poniżej.npm install unipile-node-sdkyarn dodaj unipile-node-sdkpnpm zainstaluj unipile-node-sdk# Poświadczenia Unipile (nigdy nie dodawaj tego pliku do repozytorium)
UNIPILE_DSN=https://api4.unipile.com:13444
UNIPILE_TOKEN=twój_token_dostępu_tutaj
# Identyfikator konta powiązanego konta e-mail
ID_KONTA_EMAIL=acc_xxxxxxxxxxxxxxxxDodaj .env do twojego .gitignore. Użyj dotenv lub natywny Node 20.6+ --plik-środowiskowy flaga do załadowania go: node --env-file=.env wyślij.mjs.
Konfiguracja pierwszego konta e-mail
The ujednolicone API pocztowe używa jednego account_id aby abstrakcyjnie obsłużyć różnice między dostawcami. Połącz konto raz, a następnie wywołaj client.email.send() identycznie u wszystkich trzech dostawców.
Wybierz swojego dostawcę poniżej, aby zobaczyć dokładny fragment kodu Node.js. Zwrócone `account_id` jest tym, co przechowujesz i ponownie wykorzystujesz przy każdym kolejnym wysłaniu.
import { UnipileClient } z 'unipile-node-sdk';
const klient = nowy UnipileClient(process.env.UNIPILE_DSN, process.env.UNIPILE_TOKEN);
// Krok 1: wygeneruj hostowany link OAuth dla Gmaila
const { url } = await konta klienta.utwórzPołączenieAutoryzacyjne({
typ: 'GOOGLE',
success_redirect_url: process.env.OAUTH_CALLBACK_URL,
failure_redirect_url: process.env.OAUTH_CALLBACK_URL + '?error=1',
});
// Krok 2: przekieruj użytkownika na `url`
konsola.log('Przekieruj użytkownika do:', adres URL);
// Krok 3: Unipile wysyła POST z account_id do Twojego callbacku
// Zapisz: process.env.EMAIL_ACCOUNT_ID = result.account_idimport { UnipileClient } z 'unipile-node-sdk';
const klient = nowy UnipileClient(process.env.UNIPILE_DSN, process.env.UNIPILE_TOKEN);
// Działa dla poczty Outlook osobistej ORAZ Microsoft 365 / Exchange Online
const { url } = await konta klienta.utwórzPołączenieAutoryzacyjne({
typ: 'MICROSOFT',
success_redirect_url: process.env.OAUTH_CALLBACK_URL,
failure_redirect_url: process.env.OAUTH_CALLBACK_URL + '?error=1',
});
// Przekieruj użytkownika -> dokończy przepływ Microsoft OAuth
konsola.log('Przekieruj użytkownika do:', adres URL);
// Zobacz: /syncing-emails-with-microsoft-graph-api-a-developers-guide/import { UnipileClient } z 'unipile-node-sdk';
const klient = nowy UnipileClient(process.env.UNIPILE_DSN, process.env.UNIPILE_TOKEN);
// SMTP/IMAP: podaj dane uwierzytelniające bezpośrednio (bez przekierowania OAuth)
const konto = await konta klienta.create({
typ: 'IMAP',
imap: {
username: process.env.IMAP_UŻYTKOWNIK,
hasło: process.env.HASŁO_IMAP, host: process.env.HOST_IMAP,
port: 993,
},
smtp: {
username: process.env.IMAP_UŻYTKOWNIK,
hasło: process.env.HASŁO_IMAP, host: process.env.SMTP_HOST,
port: 587,
},
});
konsola.log(account.account_id); // przechować toWysyłanie pierwszego e-maila z Node.js
Trzy gotowe do produkcji wzorce dla przepływu pracy API wysyłania wiadomości e-mail w języku JavaScript: zwykły tekst, HTML z DW/UDW i odczytywanie obiektu odpowiedzi. Wszystkie używają tych samych client.email.send() zadzwoń.
import { UnipileClient } z 'unipile-node-sdk';
const klient = nowy UnipileClient(process.env.UNIPILE_DSN, process.env.UNIPILE_TOKEN);
const wynik = await client.email.wysyłać({
account_id: process.env.ID_KONTA_EMAIL,
do: [{ display_name: 'Bob', identyfikator: 'bob@example.com' }],
temat: 'Witamy na platformie',
body: 'Cześć Bob, twoje konto jest gotowe.',
});
konsola.log(wynik.identyfikator_śledzenia); // msg_xxxxxxxxxxxxxxxxconst wynik = await client.email.wysyłać({
account_id: process.env.ID_KONTA_EMAIL,
do: [{ display_name: 'Alicja', identyfikator: 'alice@acme.com' }],
cc: [{ imię_wyświetlane: 'Kierownik', identyfikator: 'boss@acme.com' }],
dw: [{ imię_wyświetlane: 'Audyt', identyfikator: 'audit@internal.io' }],
temat: 'Twoja faktura #1042',
// Treść HTML - dostawca renderuje ją natywnie
body: `
Faktura #1042
Kwota do zapłaty: $299
Zapłać teraz
`,
});
konsola.log('Wysłano:', result.tracking_id);| Pole | Typ | Wymagany | Opis |
|---|---|---|---|
account_id | łańcuch | Wymagany | Identyfikator konta e-mail, z którego pochodzi wysyłka |
do | Odbiorcy[] | Wymagany | Tablica {nazwa_wyświetlana, identyfikator} przedmioty |
podmiot | łańcuch | Wymagany | Temat wiadomości e-mail |
ciało | łańcuch | Wymagany | Tekst zwykły czy ciąg znaków HTML |
cc | Odbiorcy[] | Opcjonalnie | DW: dwu-krotne kopiowanie |
Dw. kopia | Odbiorcy[] | Opcjonalnie | Dwóch odbiorców kopii ukrytej |
z | Odbiorca | Opcjonalnie | Przesłoń nazwę wyświetlaną nadawcy |
reply_to | łańcuch | Opcjonalnie | Identyfikator wiadomości dostawcy do odpowiedzi (wątki) |
załączniki | Tablica | Opcjonalnie | Tablica [nazwa_pliku, Bufor] krotki |
nagłówki niestandardowe | obiekt[] | Opcjonalnie | Niestandardowa tablica nagłówków X |
opcje_śledzenia | obiekt | Opcjonalnie | {otwiera, linkuje, etykieta} - włącz śledzenie otwarć/kliknięć |
Pobierz swój klucz API, połącz konto Gmail lub Outlook w ciągu kilku minut i uruchom przykłady Node.js z tego przewodnika na rzeczywistych skrzynkach pocztowych.
Wysyłanie załączników w Node.js
The załączniki pole akceptuje tablicę [nazwa_pliku, Bufor] krotki. Odczytaj plik za pomocą Node's fs.readFileSync lub przesyłaj strumieniowo z fs.promises.readFile.
fs.promises.readFile(ścieżka) aby uzyskać Bufor, następnie podaj ['nazwa_pliku.pdf', bufor]. Działa dla PDF, DOCX, obrazów, każdego formatu binarnego.cid: schemat. Odwołaj się do tej samej nazwy pliku użytej w krotce załączników: <img src="cid:logo.png">.pdfkit), zbierz go do Bufora i dołącz bez zapisywania na dysku. Bezpieczne w produkcji dla środowisk bezserwerowych.import { UnipileClient } z 'unipile-node-sdk';
import obietnice jako fs z 'node:fs';
const klient = nowy UnipileClient(process.env.UNIPILE_DSN, process.env.UNIPILE_TOKEN);
// Odczytaj plik do bufora
const buforPDF = await fs.odczytajPlik('./faktura.pdf');
czekać client.email.wysyłać({
account_id: process.env.ID_KONTA_EMAIL,
to: [{ display_name: 'Klient', identyfikator: 'client@example.com' }],
temat: 'Twoja faktura znajduje się w załączniku',
body: 'Proszę znaleźć swoją fakturę w załączniku.
',
załączniki: [
['faktura.pdf', pdfBufor], // [nazwa_pliku, Bufor]
],
});const [logo, raport] = await Obietnica.wszystkofs.odczytajPlik('/logo.png'),
fs.odczytajPlik('./raport.xlsx'),
]);
czekać client.email.wysyłać({
account_id: process.env.ID_KONTA_EMAIL,
do: [{ display_name: 'Zespół', identyfikator: 'team@acme.com' }],
temat: 'Raport Q1',
body:
Raport Q1
Szczegóły znajdują się w załączonym arkuszu kalkulacyjnym.
`,
załączniki: [
['logo.png', logo], // wbudowane przez cid:logo.png w treści
['raport.xlsx', raport], // zwykłe załącznik
],
});Odpowiedzi, Wątki i Śledzenie
Wyjdź poza proste wysyłanie: odpowiedzi na wątki, niestandardowe nagłówki dla idempotencji, śledzenie otwarć/kliknięć za pomocą webhooków oraz Wysyłanie wiadomości e-mail w imieniu użytkownika.
1
Odpowiadanie na wątek
Przekaż identyfikator wiadomości dostawcy (zwrócony w oryginalnej odpowiedzi wysyłania lub z listy wiadomości e-mail) jako reply_to. Unipile wstrzykuje prawidłowy Odpowiedź-Do oraz Bibliografia nagłówki, dzięki czemu wątki odpowiedzi prawidłowo wyświetlają się w Gmailu, Outlooku i klientach IMAP.
czekać client.email.wysyłać({
account_id: process.env.ID_KONTA_EMAIL,
do: [{ display_name: 'Alicja', identyfikator: 'alice@acme.com' }],
temat: 'Re: Twoje pytanie',
body: 'Dziękuję za kontakt! Oto odpowiedź...
',
// Id wiadomości dostawcy z oryginalnego e-maila
odpowiedz_do: 'msg_xxxxxxxxxxxxxxxx',
});
2
Niestandardowe nagłówki i idempotencja
Użycie nagłówki niestandardowe dodać jakikolwiek X- nagłówek. Powszechnym wzorcem jest Klucz-Idempotencji-X aby zapobiec powielaniu wysyłek po ponowieniu próby po przekroczeniu limitu czasu sieci.
import { losowyIdentyfikatorUUID } z 'node:crypto';
czekać client.email.wysyłać({
account_id: process.env.ID_KONTA_EMAIL,
do: [{ display_name: 'Bob', identyfikator: 'bob@example.com' }],
temat: 'Potwierdzenie zamówienia #9981',
body: 'Twoje zamówienie zostało potwierdzone.
',
niestandardowe_nagłówki: [
{ nazwa: 'Klucz-Idempotencji-X', wartość: randomUUID},
{ nazwa: 'X-Identyfikator Zamówienia', wartość: '9981' },
],
});
3
Śledzenie otwarć i kliknięć za pomocą webhooków
Włącz śledzenie w opcje_śledzenia. Unipile wysyła zdarzenie webhook (e-mail.otwarty / email.kliknięto_link) do zarejestrowanego adresu URL webhooku z etykieta Ustawiasz tutaj, aby móc powiązać zdarzenia z wewnętrznymi identyfikatorami.
czekać client.email.wysyłać({
account_id: process.env.ID_KONTA_EMAIL,
do: [{ display_name: 'Ołów', identyfikator: 'lead@prospect.com' }],
temat: 'Następstwo po Pana/Pani okresie próbnym',
body: 'Cześć, chciałem się odezwać...
',
tracking_options: {
opens: true, // uruchamia webhooka email.opened
połączenia true, // wyzwala webhook email.link_clicked
etykieta: 'crm_lead_12345', // Twój wewnętrzny identyfikator korelacji
},
});
4
Wysłano w imieniu innego użytkownika
Podczas tworzenia aplikacji SaaS wielodostępnych każdy użytkownik końcowy łączy swoje konto e-mail. Przechowuj dane account_id na użytkownika w Twojej bazie danych i przekazać go w czasie wysyłki. Zobacz pełny przewodnik po jak wysłać e-mail w imieniu użytkownika.
// Każdy użytkownik ma swój własny powiązany account_id przechowywany w Twojej bazie danych
async function wyslijJakoUzytkownik(userId, do, temat, treść) {
const użytkownik = await baza danych.PobierzUżytkownika(userId);
return client.email.wysyłać({
account_id: user.unipile_account_id, // na użytkownika
to, temat, treść,
});
}
// Email wysłany z Gmaila Alice, a nie z adresu Twojego serwera
czekać wyslijJakoUzytkownik('uzytkownik_alice', odbiorcy, temat, treść);Pracujesz w Pythonie? Zobacz nasze Implementacja w Pythonie przewodnik.
Obsługa błędów i ponawianie prób
Awarie sieci i limity szybkości są nieuniknione na dużą skalę. Oto produkcyjny wzorzec async/await dla Twojej implementacji JavaScriptowego API wysyłania wiadomości e-mail – z wykładniczym wycofywaniem i strukturalnym logowaniem przy użyciu Winston lub Pino.
identyfikator_śledzenia jest wypełniony. Nie ma potrzeby ponawiania.Ponów-Po nagłówek. Użyj wykładniczego wycofywania.UNIPILE_TOKEN zmienna środowiskowa. Nie ponawiaj próby - popraw dane uwierzytelniające.account_id nie istnieje lub został unieważniony. Ponownie połącz konto.import { UnipileClient } from 'unipile-node-sdk';
import logger from './logger.mjs'; // Winston or Pino instance
const client = new UnipileClient(process.env.UNIPILE_DSN, process.env.UNIPILE_TOKEN);
async function sendWithRetry(payload, maxAttempts = 4) {
let attempt = 0;
while (attempt < maxAttempts) {
try {
const result = await client.email.send(payload);
logger.info({ tracking_id: result.tracking_id }, 'Email sent');
return result;
} catch (err) {
const status = err?.status ?? err?.statusCode;
// Do not retry on client errors (4xx except 429)
if (status >= 400 && status !== 429 && status < 500) {
logger.error({ status, err }, 'Non-retryable error');
throw err;
}
attempt++;
if (attempt >= maxAttempts) throw err;
// Exponential backoff: 1s, 2s, 4s, 8s...
const delay = 1000 * 2 ** (attempt - 1);
logger.warn({ attempt, delay, status }, 'Retrying...');
await new Promise(r => setTimeout(r, delay));
}
}
}
// Usage
await sendWithRetry({
account_id: process.env.EMAIL_ACCOUNT_ID,
to: [{ display_name: 'User', identifier: 'user@example.com' }],
subject: 'Your report is ready',
body: 'Click to download.
',
});Najlepsze praktyki bezpieczeństwa w Node.js
Twój UNIPILE_TOKEN udziela pełnego dostępu API. Nigdy nie ujawniaj go po stronie klienta. Zobacz pełny Przewodnik po zabezpieczaniu API poczty elektronicznej do zaawansowanych tematów, w tym DKIM, SPF i rotacji tokenów OAuth.
UNIPILE_TOKEN musi pozostać na serwerze. Żaden kod JavaScript po stronie przeglądarki - w tym komponenty klienckie Next.js, frontend React ani Vite - NIE MOŻE importować tokenu bezpośrednio./api/wyślij-e-mail. W Express, endpoint POST. Najpierw uwierzytelnij własnych użytkowników, a następnie wywołaj serwer Unipile z tokenem z env.account_id pozostaje ważny. Nie musisz samodzielnie obsługiwać wygasania tokenu dostępu.// client.js - NIGDY nie rób tego
const klient = nowy UnipileClient(
'https://api4.unipile.com:13444',
'sk_live_xxxxxxxxxx' Ujawniono!
);
// app/api/send-email/route.js
eksportuj asynchroniczną funkcję POST(req) {
// najpierw sprawdź autoryzację
const session = czekać getServerSession();
if (!session) return new Response(null,{status:401});
const client = new UnipileClient(
process.env.UNIPILE_DSN, // tylko na serwerze
process.env.UNIPILE_TOKEN // tylko na serwerze
);
czekać client.email.send({...});
}
Powszechne pułapki (specyficzne dla Node.js)
Oto najczęstsze błędy popełniane przez programistów podczas pierwszej integracji API do wysyłania e-maili w JavaScript. Każdy z nich jest łatwy do uniknięcia, gdy znasz schemat – i wszystkie mają zastosowanie równie dobrze w kontekście API do wysyłania e-maili w Node.js.
czekać działa tylko w modułach ES (.mjs lub "typ":"moduł"). W CommonJS, umieść wywołanie send w asynchroniczny IIFE lub użyj .then(). SDK działa w obu przypadkach – wystarczy wybrać odpowiedni format modułu.// CommonJS: opakuj w asynchroniczną IIFE
(asynchronicznie () => {
const { UnipileClient } = await import('unipile-node-sdk');
const klient = nowy UnipileClient(process.env.UNIPILE_DSN, process.env.UNIPILE_TOKEN);
czekać client.email.wysyłać({ /* ... */ });
})();Obietnica.wszystko wysyłane jednocześnie uderzą w limity i spowodują błędy 429. Użyj limitera współbieżności, takiego jak p-ograniczenie aby ograniczyć równoległe żądania.import pLimit z 'p-limit';
const limit = pLimit(5); // maks. 5 jednoczesnych wysyłek
const wyniki = await Obietnica.wszystkoodbiorcy.mapa(r => limit(() => client.email.wysyłać({
account_id: proces.env.ID_KONTA_EMAIL,
do: [r], temat, treść,
})))
);Bufor obiekt - nie ciąg znaków base64, nie ciąg znaków UTF-8. Jeśli masz zawartość w formacie base64 (np. z webhooka lub odpowiedzi API), najpierw ją przekonwertuj: Buffer.from(base64str, 'base64').// BŁĄD: przekazywanie ciągu znaków
załączniki: [['plik.pdf', 'JVBERi0xLjQ...']] // ciąg znaków base64 - błędy!
// POPRAWNIE: Obiekt bufora
załączniki: [['plik.pdf', Bufor.z(ciąg_base64, 'base64')]]
// lub z dysku:
załączniki: [['plik.pdf', czekać fs.odczytajPlik('./plik.pdf')]]wysłać Wywołanie to spowoduje awarię procesu w Node 15+. Zawsze czekać wynik lub dołączyć .catch() Obsługa.// BŁĘDNIE: fire-and-forget - powoduje błąd w Node 15+
client.email.wysyłać(ładunek); // bez await, bez .catch()
// POPRAWNIE: zawsze obsługuj obietnicę
czekać client.email.wysyłać(ładunek) // opcja 1: await
.połów(błąd => rejestrator.błąd(err)); // opcja 2: .catch()UNIPILE_TOKEN są przeznaczone tylko dla Node.js po stronie serwera. Bezpośrednie wywołanie API przez przeglądarkę ujawni Twój token. Użyj trasy backendowej (trasy API Next.js, punktu końcowego Express, funkcji Netlify/Vercel) jako proxy.account_id Z wcześniej połączonego konta Gmail, Outlook lub IMAP. Interfejs API zwraca kod 404, jeśli identyfikator konta jest nieprawidłowy lub został odłączony.Często zadawane pytania
Najczęściej zadawane pytania dotyczące wysyłania e-maili w JavaScript i Node.js za pomocą ujednoliconego API e-mail Unipile.
unipile-node-sdk, inicjalizuj UnipileClient za pomocą Twojego DSN i tokenu połącz konto Gmail lub Outlook przez OAuth, a następnie wywołaj client.email.send(). Żaden serwer SMTP, żaden port 587, żadna konfiguracja TLS nie jest wymagana z Twojej strony - Unipile zajmuje się warstwą transportową.Nie - i nie powinieneś. Wywoływanie API Unipile z poziomu JavaScript w przeglądarce naraziłoby twoje UNIPILE_TOKEN do każdego użytkownika, który otworzy Narzędzia deweloperskie. Zawsze wywołuj interfejs API z kontekstu serwera Node.js: trasy Express, trasy API Next.js (app/api/), Vercel Edge Function lub Netlify Function.
Twój frontend wysyła żądanie do własnego punktu końcowego backendu, który uwierzytelnia sesję użytkownika, a następnie wywołuje serwer Unipile.
Nodemailer łączy się bezpośrednio z serwerem SMTP z Twojego procesu Node.js. Wymaga od Ciebie zarządzania poświadczeniami SMTP, obsługi TLS, samodzielnej konfiguracji DKIM oraz osobnego radzenia sobie z niedoskonałościami każdego dostawcy.
API pocztowe Unipile to warstwa abstrakcji w chmurze: łączysz konta przez OAuth (nie są potrzebne dane uwierzytelniające SMTP dla Gmail/Outlook), otrzymujesz jeden spójny pakiet SDK dla wszystkich dostawców, a Unipile zajmuje się transportem, ponawianiem prób i odświeżaniem tokenów. Kompromisem jest to, że Twoje wysyłki przechodzą przez infrastrukturę Unipile, a nie bezpośrednie połączenie SMTP.
Tak. Ten unipile-node-sdk paczka zawiera definicje typów TypeScript. Otrzymujesz pełne autouzupełnianie i bezpieczeństwo typów dla wysłać ładunek, w tym Odbiorca, opcje_śledzenia, i typ odpowiedzi.
import { UnipileClient } z 'unipile-node-sdk';
// Pełne typy TS – autouzupełnianie działa w VSCode
const klient: UnipileClient = nowy UnipileClient(dsn, token);
const wynik = await client.email.wysyłać({ /* wpisano! */ });W przypadku wysyłek o dużej wolumenie użyj ograniczania współbieżności (np. p-ograniczenie z 5-10 jednoczesnymi połączeniami), dodaj wykładnicze opóźnienie dla odpowiedzi 429 i rozłóż wysyłkę na wiele połączonych kont, jeśli to możliwe. Każde połączone konto e-mail ma własne limity wysyłki określone przez dostawcę (Gmail: ~500/dzień dla zwykłych kont, więcej dla Workspace).
Dla prawdziwego masowego/marketingowego wysyłania e-maili na dużą skalę (miliony odbiorców), rozważ dedykowany ESP (Mailgun, SendGrid) obok Unipile do wysyłek transakcyjnych i opartych na OAuth.
Następny.js: Użyj tras API (app/api/wyslij-email/trasa.js) lub Akcje po stronie serwera. Zachowaj tworzenie instancji SDK tylko po stronie serwera.
Nuxt użyj tras serwerowychserwer/api/send-email.post.ts). SDK jest dostępny tylko dla Node.js, więc nie może trafić do composable lub wtyczki, która działa po stronie klienta.
NestJS: stwórz ModułEmail z usługą, która opakowuje UnipileClient. Wstrzyknij to wszędzie tam, gdzie potrzebujesz wyzwalać wysyłki – w kontrolerach, zadaniach CRON lub programach obsługi zdarzeń.
Masz jeszcze jakieś pytania? Nasz zespół służy pomocą.