Jak Wyślij e-mail przez API w Python (Szybki Samouczek)
Pomiń standardowy tekst SMTP. Ten przewodnik pokazuje, jak używać Unipile ujednolicone API poczty e-mail aby wysłać e-mail w Pythonie - z przykładami copy-paste dla Gmail, Outlook i IMAP za pomocą żądania biblioteka.
import żądania, os
Klucz API = os.environ['UNIPILE_API_KEY']
DSN = os.environ['UNIPILE_DSN']
IDENTYFIKATOR_KONTA = os.environ['UNIPILE_ID_KONTA']
response = requests.stanowisko(
f'{DSN}/api/v1/emails',
nagłówki={'Klucz API X': Klucz API},
dane={
'id_konta': IDENTYFIKATOR_KONTA,
'do': '[{"display_name":"Alice","identifier":"alice@acme.com"}]',
'temat': 'Witaj z Pythona',
'ciało': 'Wysłano przez Unipile!
'
}
)
print(odpowiedź.json())5-wierszowy przykład w Pythonie
Jeśli już wiesz Czym jest API do wysyłania wiadomości e-mail i po prostu chcę działającego kodu API poczty e-mail w Pythonie, oto on. Pełny samouczek znajduje się poniżej.
pip install requests python-dotenvUNIPILE_DSN, UNIPILE_API_KEYoraz UNIPILE_ID_KONTA do twojego .env plik./api/v1/emailsaccount_id, do, podmiotoraz ciało. Zrobione.import żądania, os
z dotenv import load_dotenv
load_dotenv()
Klucz API = os.environ['UNIPILE_API_KEY']
DSN = os.environ['UNIPILE_DSN']
IDENTYFIKATOR_KONTA = os.environ['UNIPILE_ID_KONTA']
resp = requests.stanowisko(
f'{DSN}/api/v1/emails',
nagłówki={'Klucz API X': Klucz API},
dane={
'id_konta': IDENTYFIKATOR_KONTA,
'do': '[{"display_name":"Alice","identifier":"alice@acme.com"}]',
'temat': 'Witaj z Pythona',
'ciało': 'Wysłano przez Unipile!
'
}
)
print(odpowiednio.json()) # {'tracking_id': 'msg_...'}Wymagania wstępne i konfiguracja
Zanim będziesz mógł użyć przepływu pracy w Pythonie z interfejsem API poczty e-mail w środowisku produkcyjnym, potrzebujesz czterech rzeczy: Python 3.9+, żądania biblioteka, klucz API z DSN i powiązane konto e-mail.
| typów unii, oraz funkcje standardowej biblioteki z 3.9+. Python 3.11 LTS jest zalecany do produkcji. Sprawdź swoją wersję za pomocą python --version.api4.unipile.com:13444. Oba są wymagane w każdym nagłówku żądania.python -m venv .venv && source .venv/bin/activate. Nigdy nie instaluj pakietów w systemowym Pythonie – jest to szczególnie ważne przy obsłudze poświadczeń.pip install requests python-dotenv
# Opcjonalnie: wsparcie asynchroniczne
pip instal aiohttp httpx
# Opcjonalnie: logika ponawiania
pip install tenacitypipenv install requests python-dotenv tenacitypoetry dodaj żądania python-dotenv wytrwałość# Poświadczenia Unipile - nigdy nie zatwierdzaj tego pliku
UNIPILE_DSN=https://api4.unipile.com:13444
UNIPILE_API_KEY=twój_token_dostępu_tutaj
# Identyfikator konta powiązanego konta e-mail
UNIPILE_ID_KONTA=acc_xxxxxxxxxxxxxxxxDodaj .env do twojego .gitignore. Załaduj z python-dotenv przez wczytaj_zmienne_srodowiskowe() na górze swojego skryptu. W produkcji preferuj zmienne środowiskowe faktycznie wstrzykiwane przez platformę wdrażania (Heroku, Railway, Docker Compose).
Konfiguracja pierwszego konta e-mail
Zanim będziesz mógł wysyłać wiadomości, musisz połączyć konto e-mail z Unipile. Jest to jednorazowy krok dla każdego konta. Zobacz pełny Zintegrowany przewodnik po integracji interfejsu API poczty e-mail więcej o przepływach wielu kont.
Unipile używa hostowanego kreatora uwierzytelniania – Twój skrypt w Pythonie generuje link uwierzytelniający, użytkownik klika w niego i kończy proces OAuth w przeglądarce, a następnie Unipile wywołuje Twój webhook z nowymi account_id. Żadne dane uwierzytelniające SMTP do Gmaila ani Outlooka nie są przechowywane w Twoim kodzie.
import żądania, os
z dotenv import load_dotenv
load_dotenv()
Klucz API = os.environ['UNIPILE_API_KEY']
DSN = os.environ['UNIPILE_DSN']
# Krok 1: Utwórz hostowany link autoryzacyjny dla Gmail OAuth
resp = requests.stanowisko(
f'{DSN}/api/v1/hosted/accounts/link',
nagłówki={'Klucz API X': Klucz API},
dane={
'typ': 'GOOGLE',
'imię': 'Alice Gmail',
'url_powodzenia': 'https://yourapp.com/oauth/success',
'adres_błędu': 'https://yourapp.com/oauth/niepowodzenie'
}
)
# Krok 2: wyślij ten URL do użytkownika
auth_url = resp.json()['adres URL']
print(Przekieruj użytkownika do: {auth_url}')
# Krok 3: Unipile wysyła POSTy z {account_id} do Twojego webhooka po OAuth
# Zobacz /gmail-api-send-email-a-comprehensive-guide-for-developers/ dla szczegółów Gmailimport żądania, os
z dotenv import load_dotenv
load_dotenv()
# Outlook OAuth - obejmuje osobisty Outlook + Microsoft 365
# Zobacz /microsoft-graph-api-email-integration-guide/
resp = requests.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/hosted/accounts/link',
nagłówki={'Klucz API X': os.environ['UNIPILE_API_KEY']},
dane={
'typ': 'MICROSOFT',
'imię': 'Bob Outlook',
'url_powodzenia': 'https://yourapp.com/oauth/success',
'adres_błędu': 'https://yourapp.com/oauth/niepowodzenie'
}
)
print(odpowiednio.json()['adres URL'])import requests, os, json
# IMAP: przekazuj poświadczenia SMTP/IMAP bezpośrednio (przekierowanie OAuth nie jest wymagane)
# Zobacz /the-developers-guide-to-imap-api-solution/ po pełne szczegóły IMAP
resp = requests.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/accounts',
nagłówki={'Klucz API X': os.environ['UNIPILE_API_KEY']},
json={
'dostawca': 'IMAP',
'nazwa użytkownika': 'alice@company.com',
'hasło': 'hasło_aplikacji_tutaj',
'imap_host': 'imap.company.com',
'smtp_host': 'smtp.company.com'
}
)
identyfikator_konta = resp.json()['id_konta']
print(Połączone konto: {account_id}')Wysyłanie pierwszego e-maila z Pythona
Punkt końcowy wysyłania akceptuje multipart/form-data. Użyj dane= nie json=) w requests.post(). The do, ccoraz Dw. kopia pola są ciągami znaków zakodowanymi w JSON w danych formularza.
import requests, os, json
żądania.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/emails',
nagłówki={'Klucz API X': os.environ['UNIPILE_API_KEY']},
dane={
'id_konta': os.environ['UNIPILE_ID_KONTA'],
'do': json.zrzuty([{'nazwa_wyświetlana': 'Alicja', 'identyfikator': 'alice@acme.com'}]),
'temat': 'Szybka aktualizacja',
'ciało': 'Cześć Alice, tylko się odzywam.'
}
)ciało pole akceptuje zarówno zwykły tekst, jak i kod HTML. Użyj tagi formatowania HTML.import requests, os, json
response = requests.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/emails',
nagłówki={'Klucz API X': os.environ['UNIPILE_API_KEY']},
dane={
'id_konta': os.environ['UNIPILE_ID_KONTA'],
'do': json.zrzuty([{'identyfikator': 'alice@acme.com'}]),
'Dwój dwój': json.zrzuty([{'identyfikator': 'manager@acme.com'}]),
'DW': json.zrzuty([{'identyfikator': 'crm@yourapp.com'}]),
'temat': 'Twoja faktura jest gotowa',
'ciało': 'Faktura #1042
Proszę znaleźć swoją fakturę w załączniku.
'
}
)
# 202 Zaakceptowano = kolejkowane do dostarczenia
print(status_kodu_odpowiedzi, odpowiedź.json())import requests, os, json
def wyślij_e-maildo_email: str, temat: str, ciało: str) -> słownik:
"Wyślij e-mail za pomocą Python wrappera API e-mail Unipile."
response = requests.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/emails',
nagłówki={'Klucz API X': os.environ['UNIPILE_API_KEY']},
dane={
'id_konta': os.environ['UNIPILE_ID_KONTA'],
'do'json.zrzuty([{'identyfikator': do_email}]),
'temat'temat,
'ciało'ciało,
},
timeout=30
)
odzew.podnieś_status() # podnosi HTTPError przy statusach 4xx/5xx
return odzew.json() # {'tracking_id': 'msg_...'}timeout=30 aby uniknąć wiecznego zawieszania się z powodu problemów z siecią. Użyj podnieś_status przechowywać błędy HTTP jako wyjątki w Pythonie.Uzyskaj klucz API, połącz konto Gmail lub Outlook w kilka minut i uruchom przykłady Pythona z tego przewodnika na rzeczywistych skrzynkach pocztowych.
Wysyłanie załączników w Pythonie
Załączniki są wysyłane jako część danych formularza wieloczęściowego przy użyciu Pythona pliki= parametr. Otwórz plik w trybie binarnym ('rb') - bajty, nie ciągi znaków.
import requests, os, json
# Pojedynczy plik załącznika
z otwórz('faktura.pdf', 'rb') jako f:
resp = requests.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/emails',
nagłówki={'Klucz API X': os.environ['UNIPILE_API_KEY']},
dane={
'id_konta': os.environ['UNIPILE_ID_KONTA'],
'do': json.zrzuty([{'identyfikator': 'client@example.com'}]),
'temat': 'Faktura w załączeniu',
'ciało': 'Proszę zobaczyć załączoną fakturę.
'
},
pliki={'załączniki': ('faktura.pdf', f, 'application/pdf')}
)
# Multiple attachments: pass a list of tuples
# pliki=[('załączniki', ('a.pdf', f1, 'application/pdf')),
# [('załączniki', ('b.png', f2, 'image/png'))]open('file.pdf', 'rb'), nie 'er'. Przekazanie obiektu pliku tekstowego do pliki= podnosi Błąd typu. To częsta pułapka specyficzna dla Pythona podczas migracji z biblioteki smtplib.pliki=każda krotka jest ('załączniki', (nazwa_pliku, obiekt_pliku, typ_zawartości)). Requests automatycznie obsługuje granicę wieloczęściową.BytesIO obiekt bezpośrednio from io import BytesIO; buf = BytesIO(pdf_bytes) wtedy ('raport.pdf', buf, 'application/pdf').Odpowiedzi, Wątki i Śledzenie
Dla Wysyłanie wiadomości e-mail w imieniu użytkownika, wątkowanie i śledzenie dostaw oparte na webhookach, oto wzorce języka Python, których potrzebujesz.
01Wątkowanie z in_reply_to
Aby odpowiedzieć w istniejącym wątku, przekaż w odpowiedzi na pole z identyfikator_śledzenia e-mail, na który chcesz odpowiedzieć. Unipile obsługuje Bibliografia oraz Odpowiedź-Do nagłówki automatycznie.
żądania.stanowisko(
f'{DSN}/api/v1/emails',
nagłówki={'Klucz API X': Klucz API},
dane={
'id_konta': IDENTYFIKATOR_KONTA,
'do': json.zrzuty([{'identyfikator': 'alice@acme.com'}]),
'temat': 'Re: Twoje pytanie',
'ciało': 'Nawiązując do Twojej wiadomości.
',
'odpowiedź_na': 'id_śledzenia_oryginalny'
}
)02Webhooki w Pythonie (przykład z Flaskiem)
Zarejestruj adres URL webhooka w swoim panelu Unipile, aby otrzymywać zdarzenia dostarczenia (wysłane, odrzucone, otwarte). Oto minimalny odbiornik Flask:
z kieliszek import Flask, request, jsonify
import logowanie
aplikacja = Flaszka(__imię__)
rejestrowanie.basicConfigpoziom=logging.INFORMACJA)
@aplikacja.trasa('/webhook/email', methods=['POST'])
def email_webhook():
zdarzenie = żądanie.get_json()
typ_zdarzenia = zdarzenie.uzyskać('typ')
tracking_id = zdarzenia.uzyskać('śledzący_id')
rejestrowanie.informacje(f'Email z wydarzeniem: {event_type} dla {tracking_id}')
return jsonify(zgoda=Prawda), 20003Klucze idempotencji
Aby zapobiec wielokrotnemu wysyłaniu podczas ponawiania próby sieci, przekaż unikalny Klucz idempotencji Nagłówek. Jeśli ten sam klucz zostanie wysłany dwukrotnie, Unipile zwróci pierwotną odpowiedź bez wysyłania drugiej wiadomości e-mail.
import uuid, żądania, os, json
klucz = stridentyfikator UUID.uuid4()) # generuj raz, przechowuj w bazie danych
żądania.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/emails',
nagłówki={
'Klucz API X'os.environ['UNIPILE_API_KEY'],
'Idempotency-Key'Klucz
},
dane={'id_konta': os.environ['UNIPILE_ID_KONTA'],
'do': json.zrzuty([{'identyfikator': 'alice@acme.com'}]),
'temat': 'Witamy!', 'ciało': 'Cześć!'}
)Obsługa błędów i ponawianie prób
Kod produkcyjny API e-mail wymaga prawidłowej obsługi wyjątków, strukturalnego logowania i automatycznych ponownych prób z wykładniczym wycofywaniem za pomocą wytrwałość biblioteka.
| Kod HTTP | Znaczenie | Akcja |
|---|---|---|
| 202 | Zaakceptowano - kolejkowane do dostarczenia | Przechowaj identyfikator śledzenia |
| 400 | Nieprawidłowe żądanie (nieprawidłowe pola) | Popraw ładunek, nie próbuj ponownie |
| 401 | Nieprawidłowy klucz API | Sprawdź UNIPILE_API_KEY |
| 403 | Konto nieautoryzowane | Połącz ponownie konto |
| 404 | Nie znaleziono identyfikatora konta | Sprawdź UNIPILE_ACCOUNT_ID |
| 429 | Ograniczony limit | Wycofaj się + ponów próbę (patrz kod) |
| 500 | Błąd serwera | Ponów próbę po 5 sekundach opóźnienia |
import żądania, os, json, logowanie
z wytrwałość import (
ponów, zatrzymaj_po_próbie,
wait_exponential, retry_if_exception_type
)
rejestrowanie.basicConfigpoziom=logging.INFORMACJA)
logger = logging.pobierzLoger(__imię__)
klasa BłądLimitUstawień(Wyjątek):
przejść
@ponów(
zatrzymaćzatrzymaj_po_próbie(4),
czekaj=czekaj_wykładniczo(mnożnik=1, min=2, maks=30),
ponówponów_jeśli_typ_wyjątku(BłądLimitUstawień)
)
def wyślij_z_ponowieniem(do: str, temat: str, ciało: str) -> słownik:
resp = requests.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/emails',
nagłówki={'Klucz API X': os.environ['UNIPILE_API_KEY']},
dane={
'id_konta': os.environ['UNIPILE_ID_KONTA'],
'do'json.zrzuty([{'identyfikator': do}]),
'temat'temat, 'ciało'ciało
},
timeout=30
)
jeśli resp.status_code == 429:
rejestrator.ostrzeżenie('Ograniczono liczbę żądań, wycofuję się...')
wzrastać BłądLimitUstawień()
lub.podnieś_status()
return lub.json()Najlepsze praktyki bezpieczeństwa w Pythonie
Aby uzyskać pełny przewodnik po ochronie integracji API poczty e-mail, zobacz Przewodnik po zabezpieczaniu API poczty elektronicznej. Oto podstawy specyficzne dla Pythona.
os.environ lub python-dotenv. Nigdy nie kładź UNIPILE_API_KEY jako literał ciągu znaków w kodzie źródłowym. Jeśli przypadkowo trafi na Git, natychmiast obróć klucz z poziomu panelu.venv lub conda. Zapobiega to atakom polegającym na pomieszaniu zależności i sprawia, że Twoje requirements.txt audytowalny. Zapewnij wersje w produkcji.UNIPILE_API_KEY ważny.identyfikator_śledzenia dla każdego wysłanego e-maila, aby włączyć audyty dostarczenia. Użyj standardowych technik Pythona logowanie moduł - nigdy druk() w produkcji. Wysyłaj dzienniki do SIEM do zastosowań wymagających dużej zgodności.Typowe pułapki specyficzne dla Pythona
Oto najczęstsze błędy popełniane przez programistów Pythona podczas integrowania API poczty e-mail. Jeśli zamiast tego korzystasz z Node.js, zobacz nasze JavaScript API do wysyłania poczty e-mail tutorial.
json= zamiast dane=multipart/form-data, nie JSON. Zawsze używaj requests.post(..., data={...}). Używanie json={...} zwróci błąd 400. do, ccoraz Dw. kopia pola są ciągami znaków JSON w danych formularza - użyj json.dumps() aby zakodować tablicę odbiorców.open('file.pdf', 'rb') - tryb binarny. Tryb tekstowy'er') podnosi
) powoduje
) wzbudza Błąd typu po przekazaniu do pliki= parametru. Dla zawartości w pamięci, użyj io.BytesIO.żądania biblioteka jest synchroniczna. Wywołanie jej wewnątrz asynchroniczne def funkcja blokuje pętlę zdarzeń. Użyj httpx.AsyncClient lub aiohttp.ClientSession dla asynchronicznych kontekstów Pythona (FastAPI, asynchroniczne widoki Django, skrypty asyncio).requests.post() czeka wiecznie. Zawieszone połączenie zablokuje twój wątek (lub pracownika Celery) w nieskończoność. Zawsze przekazuj timeout=30 (limit czasu połączenia, limit czasu odczytu w sekundach).from datetime import datetime, timezone; datetime.now(timezone.utc). Naiwne daty i godziny powodują ciche błędy "off-by-hours" wdrożeń wieloregionalnych.concurrent.futures.ThreadPoolExecutor) lub oddelegować do kolejki Celery.Często zadawane pytania
Najczęściej zadawane pytania dotyczące korzystania z API poczty e-mail w Pythonie z ujednoliconym API poczty e-mail Unipile.
Użyj ujednoliconego API poczty e-mail Unipile zamiast smtplib lub bezpośredniego połączenia SMTP. Zainstaluj żądania, pobierz swój klucz API i DSN z pulpitu nawigacyjnego Unipile, połącz konto Gmail lub Outlook za pomocą OAuth, a następnie wyślij POST na adres /api/v1/emails z twoim account_id, do, podmiotoraz ciało. Żaden serwer SMTP, żaden port 587, żadna konfiguracja TLS nie jest potrzebna w twoim kodzie Pythona.
Django: wywołaj API we widoku lub poleceniu zarządzania. W przypadku asynchronicznego Django (3.1+) użyj httpx.AsyncClient w asynchronicznych widokach.
Piwko Wywołuj API w obsługującym trasę programie po stronie serwera. Nigdy nie wywołuj go z szablonu Jinja ani z kodu JavaScript po stronie klienta. Użyj Flask-Celery do oddelegowania masowych wysyłek do pracowników w tle.
FastAPI: użyj httpx.AsyncClient wewnątrz asynchroniczne def końcówki. Synchroniczne żądania biblioteka blokuje asynchroniczną pętlę zdarzeń - zawsze używaj asynchronicznego klienta HTTP w FastAPI.
smtplib łączy się bezpośrednio z serwerem SMTP z Twojego procesu Pythona. Zarządzasz poświadczeniami SMTP, konfiguracją TLS i specyfiką poszczególnych dostawców (hasła aplikacji Gmail, nowoczesne uwierzytelnianie Outlook). Jest też tylko synchroniczny.
API pocztowe Unipile to abstrakcja chmurowa: połącz konta przez OAuth (bez danych logowania SMTP w Twoim kodzie dla Gmail/Outlook), uzyskaj jednolity, spójny interfejs HTTP API dla wszystkich dostawców, a Unipile zajmie się transportem, odświeżaniem tokenów i ponownymi próbami. Kompromisem jest to, że wysyłki będą kierowane przez infrastrukturę Unipile zamiast bezpośredniego połączenia SMTP.
Tak, ale potrzebujesz asynchronicznego klienta HTTP – standardowego żądania biblioteka jest synchroniczna i zablokuje twoją pętlę zdarzeń. Użyj httpx (zalecana, asynchroniczna alternatywa typu drop-in) lub aiohttp.
import httpx, os, json
asynchroniczne def wyślij_email_asynchronicznie(do: str, temat: str, ciało: str):
async with httpx.AsyncClient() jako klient:
odp = czekać klient.stanowisko(
f'{os.environ["UNIPILE_DSN"]}/api/v1/emails',
nagłówki={'Klucz API X': os.environ['UNIPILE_API_KEY']},
dane={'id_konta': os.environ['UNIPILE_ID_KONTA'],
'do': json.zrzuty([{'identyfikator': do}]),
'temat'temat, 'ciało'ciało
)
lub.podnieś_status()
return lub.json()Użyj kolejki zadań Celery z brokerem Redis lub RabbitMQ. Każdy e-mail staje się zadaniem – Celery automatycznie zarządza równoległością i ponownymi próbami. Ogranicz równoległość na pracownika, aby uniknąć limitów wysyłania (zazwyczaj 5-10 równoczesnych wysyłek na powiązane konto). W przypadku wysyłek marketingowych o bardzo dużej skali (miliony dziennie), połącz Unipile do transakcyjnych wysyłek opartych na OAuth z dedykowanym ESP do kampanii masowych.
W przypadku lżejszych zastosowań, concurrent.futures.ThreadPoolExecutor(max_workers=5) z żądania biblioteka to prostsze podejście, które eliminuje narzut Celery.
Tak. Stwórz zadanie Celery, które wywoła requests.post() do punktu końcowego Unipile. Procesy robocze Celery to standardowe synchroniczne procesy Pythona, więc żądania działa idealnie. Użyj wbudowanych funkcji Celery autoretry_for=(requests.exceptions.HTTPError,) z max_prób=3 oraz domyślne_opóźnienie_ponownej_próby=5 do automatycznego ponawiania prób w przypadku tymczasowych błędów. Połącz z Klucz idempotencji nagłówki zapobiegające wielokrotnemu wysyłaniu danych po ponownym uruchomieniu pracowników.
Masz jeszcze jakieś pytania? Nasz zespół służy pomocą.