Hoe te E-mail verzenden via API in Python (Snelle Tutorial)
Sla de SMTP-boilerplate over. Deze handleiding laat zien hoe je de Unipile uniforme e-mail API e-mail verzenden in Python - met copy-paste voorbeelden voor Gmail, Outlook en IMAP met de verzoekt bibliotheek.
importeer verzoeken, os
API_SLEUTEL = os.environ['UNIPILE_CONTROLSLEUTEL']
DSN = os.environ['UNIPILE_DSN']
ACCOUNT_ID = os.environ['UNIPILE_ACCOUNT_ID']
response = requests.post(
f'{DSN}/api/v1/emails',
headers={'X-API-KEY': API_SLEUTEL},
data={
'account_id': ACCOUNT_ID,
'naar': '[{"display_name":"Alice","identifier":"alice@acme.com"}]',
'onderwerp': 'Hallo vanuit Python',
'lichaam': 'Verzonden via Unipile!
'
}
)
print(antwoord.json())5-regelig Python-voorbeeld
Als je het al weet wat een API voor het verzenden van e-mails is en wil alleen de Python-code voor de e-mail-API die daadwerkelijk werkt, hier is deze. De volledige tutorial volgt hieronder.
pip installeert requests python-dotenvUNIPILE_DSN, UNIPILE_API_SLEUTELen UNIPILE_ACCOUNT_ID naar jou .env bestand./api/v1/emailsaccount_id, naar, onderwerpen lichaam. Klaar.importeer verzoeken, os
van dotenv importeer load_dotenv
load_dotenv()
API_SLEUTEL = os.environ['UNIPILE_CONTROLSLEUTEL']
DSN = os.environ['UNIPILE_DSN']
ACCOUNT_ID = os.environ['UNIPILE_ACCOUNT_ID']
resp = verzoeken.post(
f'{DSN}/api/v1/emails',
headers={'X-API-KEY': API_SLEUTEL},
data={
'account_id': ACCOUNT_ID,
'naar': '[{"display_name":"Alice","identifier":"alice@acme.com"}]',
'onderwerp': 'Hallo vanuit Python',
'lichaam': 'Verzonden via Unipile!
'
}
)
print(resp.json()) # {'tracking_id': 'msg_...'}Vereisten en installatie
Voordat je de e-mail API Python workflow in productie kunt gebruiken, heb je vier dingen nodig: Python 3.9+, de verzoekt bibliotheek, een API-sleutel met DSN en een gekoppeld e-mailaccount.
| union-types, en standaardbibliotheekfuncties uit 3.9+. Python 3.11 LTS wordt aanbevolen voor productie. Controleer uw versie met python --versie.api4.unipile.com:13444. Ze zijn beide vereist in elke request header.python -m venv .venv && source .venv/bin/activate. Installeer nooit pakketten in de systeem-Python - dit is vooral belangrijk voor het omgaan met inloggegevens.pip installeert requests python-dotenv
# Optioneel: asynchrone ondersteuning
pip install aiohttp httpx
# Optioneel: opnieuw proberen logica
pip install tenacitypipenv install requests python-dotenv tenacitypoetry add requests python-dotenv tenacity# Unipile-credentials - commit dit bestand nooit
UNIPILE_DSN=https://api4.unipile.com:13444
UNIPILE_API_SLEUTEL=uw_toegangstoken_hier
# Het account-ID van het gekoppelde e-mailaccount
UNIPILE_ACCOUNT_ID=acc_xxxxxxxxxxxxxxxxToevoegen .env naar jou .gitignore. Laden met python-dotenv via load_dotenv() bovenaan je script. Gebruik in productie bij voorkeur echte omgevingsvariabelen die door je deploymentplatform (Heroku, Railway, Docker Compose) worden geïnjecteerd.
Uw eerste e-mailaccount verbinden
Voordat u kunt verzenden, moet u een e-mailaccount koppelen aan Unipile. Dit is een eenmalige stap per account. Zie de volledige Geleide integratiehandleiding voor unified e-mail-API voor meer over multi-account flows.
Unipile gebruikt een gehoste authenticatiewizard - uw Python-script genereert een authenticatielink, de gebruiker klikt erop en voltooit OAuth in de browser, waarna Unipile uw webhook aanroept met de nieuwe account_id. Er worden geen SMTP-gegevens voor Gmail of Outlook opgeslagen in uw code.
importeer verzoeken, os
van dotenv importeer load_dotenv
load_dotenv()
API_SLEUTEL = os.environ['UNIPILE_CONTROLSLEUTEL']
DSN = os.environ['UNIPILE_DSN']
# Stap 1: maak een gehoste authenticatielink voor Gmail OAuth
resp = verzoeken.post(
f'{DSN}/api/v1/hosted/accounts/link',
headers={'X-API-KEY': API_SLEUTEL},
data={
'type': 'GOOGLE',
'naam': 'Alice Gmail',
'succes_url': 'https://jouwapp.com/oauth/success',
'fout_url': 'https://yourapp.com/oauth/failure'
}
)
# Stap 2: stuur deze URL naar uw gebruiker
auth_url = resp.json()['url']
print('Stuur de gebruiker rechtstreeks naar: {auth_url}')
# Stap 3: Unipile POSTs {account_id} naar uw webhook na OAuth
# Zie /gmail-api-send-email-a-comprehensive-guide-for-developers/ voor Gmail-detailsimporteer verzoeken, os
van dotenv importeer load_dotenv
load_dotenv()
# Outlook OAuth - behandelt persoonlijke Outlook + Microsoft 365
# Zie /microsoft-graph-api-email-integration-guide/
resp = verzoeken.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/hosted/accounts/link',
headers={'X-API-KEY'os.environ['UNIPILE_CONTROLSLEUTEL']},
data={
'type': 'MICROSOFT',
'naam': 'Bob Outlook',
'succes_url': 'https://jouwapp.com/oauth/success',
'fout_url': 'https://yourapp.com/oauth/failure'
}
)
print(resp.json()['url'])importeer verzoeken, os, json
# IMAP: SMTP/IMAP-gegevens rechtstreeks doorgeven (geen OAuth-omleiding nodig)
# Zie /the-developers-guide-to-imap-api-solution/ voor volledige IMAP-details
resp = verzoeken.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/accounts',
headers={'X-API-KEY'os.environ['UNIPILE_CONTROLSLEUTEL']},
json={
'provider': 'IMAP',
'gebruikersnaam': 'alice@company.com',
'wachtwoord': 'wachtwoord_app_hier',
'imap_host': 'imap.company.com',
'smtp_host': 'smtp.company.com'
}
)
account_id = resp.json()['account_id']
print(Gekoppeld account: {account_id}')Je eerste e-mail verzenden vanuit Python
Het verzendende eindpunt accepteert multipart/formulier-data. Gebruik gegevens= (niet json) in requests.post(). De naar, ccen cc velden zijn JSON-gecodeerde strings binnen de formuliergegevens.
importeer verzoeken, os, json
verzoeken.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/e-mails',
headers={'X-API-KEY'os.environ['UNIPILE_CONTROLSLEUTEL']},
data={
'account_id'os.environ['UNIPILE_ACCOUNT_ID'],
'naar': json.dumps([{'weergavenaam': 'Alice', 'identificatiecode': 'alice@acme.com'}]),
'onderwerp': 'Snelle update',
'lichaam': 'Hoi Alice, even een berichtje.'
}
)lichaam veld accepteert zowel platte tekst als HTML. Gebruik Html opmaak tags.importeer verzoeken, os, json
response = requests.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/e-mails',
headers={'X-API-KEY'os.environ['UNIPILE_CONTROLSLEUTEL']},
data={
'account_id'os.environ['UNIPILE_ACCOUNT_ID'],
'naar'json.dumps([{'identificatiecode': 'alice@acme.com'}]),
'cc'json.dumps([{'identificatiecode': 'manager@acme.com'}]),
'Cc': json.dumps([{'identificatiecode': 'crm@yourapp.com'}]),
'onderwerp': 'Uw factuur is gereed',
'lichaam': 'Factuur #1042
U vindt uw factuur bijgevoegd.
'
}
)
# 202 Geaccepteerd = in wachtrij voor levering
print(response.status_code, response.json())importeer verzoeken, os, json
def e-mail_verzenden(naar_e-mail: straal, onderwerp: straal, lichaam: straal) -> dictee:
"E-mail verzenden via de Unipile e-mail API Python wrapper."
response = requests.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/e-mails',
headers={'X-API-KEY'os.environ['UNIPILE_CONTROLSLEUTEL']},
data={
'account_id'os.environ['UNIPILE_ACCOUNT_ID'],
'naar': json.dumps([{'identificatiecode': naar_e_mail}]),
'onderwerp'onderwerp,
'lichaam'lichaam,
},
time-out=30
)
antwoord.raise_for_status() # geeft een HTTPError bij 4xx/5xx
return antwoord.json() # {'tracking_id': 'msg_...'}time-out=30 om te voorkomen dat het voor altijd vastloopt op netwerkproblemen. Gebruik raise_for_status() om HTTP-fouten te ‘bubbelen’ als Python-uitzonderingen.Verkrijg uw API-sleutel, koppel een Gmail- of Outlook-account in enkele minuten aan en voer de Python-voorbeelden uit deze gids uit tegen echte postbussen.
Bijlagen versturen in Python
Bijlagen worden als onderdeel van de multipart form data verzonden met behulp van Python's bestanden= parameter. Open het bestand in binaire modus ('rb') - bytes, geen strings.
importeer verzoeken, os, json
# Enkele bestandsbijlage
met open('factuur.pdf', 'rb') als v:
resp = verzoeken.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/e-mails',
headers={'X-API-KEY'os.environ['UNIPILE_CONTROLSLEUTEL']},
data={
'account_id'os.environ['UNIPILE_ACCOUNT_ID'],
'naar': json.dumps([{'identificatiecode': 'client@example.com'}]),
'onderwerp': 'Factuur bijgevoegd',
'lichaam': 'Zie de bijgevoegde factuur.
'
},
bestanden={'bijlagen': ('factuur.pdf', f, 'application/pdf')}
)
# Meerdere bijlagen: geef een lijst van tuples door
# bestanden=[('bijlagen', ('a.pdf', f1, 'application/pdf')),
# ('bijlagen', ('b.png', f2, 'image/png'))]open('file.pdf', 'rb'), niet 'r'. Een tekstbestandsobject doorgeven aan bestanden= verheft TypeError. Dit is een veelvoorkomende Python-specifieke valkuil bij het migreren van smtplib.bestanden=: elke tuple is ('bijlagen', (bestandsnaam, bestandsobject, inhoudstype)). Requests verwerkt de multipart grens automatisch.BytesIO rechtstreeks object from io import BytesIO; buf = BytesIO(pdf_bytes) dan ('rapport.pdf', buf, 'applicatie/pdf').Antwoorden, Threads & Tracking
Voor e-mail verzenden namens een gebruiker, threading, en webhook-gebaseerde leveringstracking, dit zijn de Python-patronen die je nodig hebt.
01Threaden met in_reply_to
Om te antwoorden binnen een bestaande thread, geef de in_reply_to veld met de tracking_id van de e-mail waarop je wilt antwoorden. Unipile regelt de Referenties en In-Reply-To automatische koppen.
verzoeken.post(
f'{DSN}/api/v1/emails',
headers={'X-API-KEY': API_SLEUTEL},
data={
'account_id': ACCOUNT_ID,
'naar': json.dumps([{'identificatiecode': 'alice@acme.com'}]),
'onderwerp': 'Re: Uw vraag',
'lichaam': 'Ter opvolging van uw bericht.
',
'in_reply_to': 'originele_tracking_id_bericht'
}
)02Webhooks in Python (Flask voorbeeld)
Registreer een webhook-URL in uw Unipile-dashboard om leveringsgebeurtenissen (verzonden, gebounced, geopend) te ontvangen. Hier is een minimale Flask-ontvanger:
van kolf importeer Flask, verzoek, jsonify
importeer loggen
app = Fles(__naam__)
loggen.basicConfigniveau=logging.INFORMATIE)
@app.route('/webhook/email', methoden=[POST])
def e-mail webhook():
gebeurtenis = verzoek.haal_json()
event_type = event.krijgen('type')
tracking_id = event.krijgen('tracking_id')
loggen.info(f'E-mail gebeurtenis: {event_type} voor {tracking_id}')
return jsonificerenok=Waar), 20003Idempotentie sleutels
Om dubbele verzendingen bij netwerkherhaling te voorkomen, geef een uniek Idempotentie-sleutel header. Als dezelfde sleutel twee keer wordt verzonden, stuurt Unipile het oorspronkelijke antwoord terug zonder een tweede e-mail te verzenden.
importeer uuid, requests, os, json
sleutel = straal(uuid.uuid4()) # eenmaal genereren, opslaan in DB
verzoeken.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/e-mails',
headers={
'X-API-KEY': os.environ['UNIPILE_CONTROLSLEUTEL'],
'Idempotentie-sleutel'sleutel
},
data={'account_id'os.environ['UNIPILE_ACCOUNT_ID'],
'naar': json.dumps([{'identificatiecode': 'alice@acme.com'}]),
'onderwerp': 'Welkom!', 'lichaam': 'Hoi!'}
)Foutafhandeling en Opnieuw proberen
Productie Python-code voor de e-mail-API heeft correcte uitzonderingsafhandeling, gestructureerde logging en automatische herhalingen met exponentiële backoff nodig. doorzettingsvermogen bibliotheek.
| HTTP-code | Betekenis | Actie |
|---|---|---|
| 202 | Geaccepteerd - in wachtrij voor levering | Opslaan tracking_id |
| 400 | Ongeldige aanvraag (ongeldige velden) | Payload corrigeren, niet opnieuw proberen |
| 401 | Ongeldige API-sleutel | Controleer UNIPILE_API_KEY |
| 403 | Account niet gemachtigd | Account opnieuw koppelen |
| 404 | Account ID niet gevonden | Controleer UNIPILE_ACCOUNT_ID |
| 429 | Rate Limiter | Terugvallen + opnieuw proberen (zie code) |
| 500 | Serverfout | Probeer het opnieuw na 5s vertraging |
importeer requests, os, json, logging
van doorzettingsvermogen importeer (
opnieuw proberen, stoppen na poging,
wacht_exponentieel, probeer_opnieuw_bij_exceptietype
)
loggen.basicConfigniveau=logging.INFORMATIE)
logger = logging.getLogger(__naam__)
klasse RateLimitError(Uitzondering):
pas
@probeer opnieuw(
stopstop_na_poging(4),
wacht=wacht_exponentieel(vermenigvuldiger=1, min=2, max=30),
opnieuw proberen=probeer_opnieuw_bij_exceptie(RateLimitError)
)
def versturen_met_herhaalpogingAan: straal, onderwerp: straal, lichaam: straal) -> dictee:
resp = verzoeken.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/e-mails',
headers={'X-API-KEY'os.environ['UNIPILE_CONTROLSLEUTEL']},
data={
'account_id'os.environ['UNIPILE_ACCOUNT_ID'],
'naar': json.dumps([{'identificatiecode': naar}]),
'onderwerp'onderwerp, 'lichaam': lichaam
},
time-out=30
)
als resp.status_code == 429:
logger.waarschuwing('Rate limited, backing off...')
verhogen RateLimitError()
resp.raise_for_status()
return resp.json()Beveiligingsbeste praktijken in Python
Voor een complete gids over het beveiligen van je e-mail API-integratie, zie de e-mail API beveiligingshandleiding. Hier zijn de Python-specifieke essentiële zaken.
os.environ of python-dotenv. Nooit zetten UNIPILE_API_SLEUTEL als een string-literal in uw broncode. Als de sleutel per ongeluk naar Git wordt gepusht, roteer deze dan onmiddellijk vanuit uw dashboard.venv of conda. Dit voorkomt dependency confusion aanvallen en maakt jouw vereisten.txt controleerbaar. Vastzetten van versies in productie.UNIPILE_API_SLEUTEL geldig.tracking_id voor elke verzonden e-mail om afleveringscontroles mogelijk te maken. Gebruik Python's standaard loggen module - nooit print() in productie. Verzamel logs naar een SIEM voor compliance-intensieve use cases.Veelvoorkomende Python-Specifieke Valkuilen
Dit zijn de meest voorkomende fouten die Python-ontwikkelaars maken bij het integreren van de e-mail-API. Als je in plaats daarvan Node.js gebruikt, raadpleeg dan onze JavaScript e-mail verzenden API-tutorial.
json in plaats van gegevens=multipart/formulier-data, geen JSON. Gebruik altijd requests.post(..., data={...}). gebruiken json={...} zal een 400-fout retourneren. De naar, ccen cc velden zijn JSON-strings binnen de formuliergegevens - gebruik json.dumps() om de ontvanger-array te coderen.open('file.pdf', 'rb') - binaire modus. Tekstmodus ('r') roept een op TypeError wanneer doorgegeven aan de bestanden= parameter. Voor inhoud in het geheugen, gebruik io.BytesIO.verzoekt bibliotheek synchroon. Het aanroepen ervan binnen een async def verstoort de event loop. Gebruik httpx.AsyncClient of aiohttp.ClientSession voor asynchrone Python-contexten (FastAPI, asynchrone Django-views, asyncio-scripts).requests.post() wacht eeuwig. Een verbroken verbinding blokkeert uw thread (of Celery-worker) voor onbepaalde tijd. Geef altijd mee time-out=30 (verbindings time-out, lees time-out in seconden).from datetime import datetime, timezone; datetime.now(timezone.utc). Nare datums veroorzaken stille fouten van uren verschil in implementaties in meerdere regio's.concurrent.futures.ThreadPoolExecutor) of offload naar een Celery-wachtrij.Veelgestelde vragen
Veelgestelde vragen over het gebruik van de e-mail API in Python met de Unipile unified e-mail API.
Gebruik de Unipile unified email API in plaats van smtplib of een directe SMTP-verbinding. Install verzoekt, haal uw API-sleutel en DSN op uit het Unipile-dashboard, koppel een Gmail- of Outlook-account via OAuth en stuur vervolgens een POST-aanvraag naar /api/v1/emails met jouw account_id, naar, onderwerpen lichaam. Geen SMTP-server, geen poort 587, geen TLS-configuratie nodig in je Python-code.
Django: roep de API aan in een view of management command. Voor async Django (3.1+) gebruikt u httpx.AsyncClient in asynchrone weergaven.
Fles Roep de API aan in een route handler aan de serverzijde. Roep deze nooit aan vanuit een Jinja-template of client-side Javascript. Gebruik Flask-Celery om grote hoeveelheden verzendingen naar achtergrondwerkers te offloaden.
FastAPI: gebruik httpx.AsyncClient binnen async def endpoints. De synchrone verzoekt Bibliotheken blokkeren de asynchrone event loop - gebruik altijd een asynchrone HTTP-client in FastAPI.
smtplib maakt rechtstreeks verbinding met een SMTP-server vanuit je Python-proces. Je beheert SMTP-referenties, TLS-instellingen en provider-specifieke eigenaardigheden (Gmail app-wachtwoorden, Outlook modern auth). Het is ook alleen synchroon.
De Unipile e-mail API is een cloudabstractie: koppel accounts via OAuth (geen SMTP-gegevens in uw code voor Gmail/Outlook), krijg één consistente HTTP API voor alle providers, en Unipile regelt transport, tokenvernieuwing en hertentingen. De keerzijde is dat verzendingen via de infrastructuur van Unipile lopen in plaats van een directe SMTP-verbinding.
Ja, maar je hebt een asynchrone HTTP-client nodig - de standaard verzoekt bibliotheek is synchroon en zal uw event loop blokkeren. Gebruik httpx (aanbevolen, direct inzetbare asynchrone alternatief) of aiohttp.
importeer httpx, os, json
async def e-mail_verzenden_asynchroonAan: straal, onderwerp: straal, lichaam: straal):
async with httpx.AsyncClient() als klant:
resp = wacht op klant.post(
f'{os.environ["UNIPILE_DSN"]}/api/v1/e-mails',
headers={'X-API-KEY'os.environ['UNIPILE_CONTROLSLEUTEL']},
data={'account_id'os.environ['UNIPILE_ACCOUNT_ID'],
'naar': json.dumps([{'identificatiecode': naar}]),
'onderwerp'onderwerp, 'lichaam': lichaam
)
resp.raise_for_status()
return resp.json()Gebruik een Celery taakwachtrij met een Redis of RabbitMQ broker. Elke e-mail wordt een taak - Celery regelt automatisch de concurrentie en herhalingen. Beperk de concurrentie per worker om snelheidslimieten te vermijden (doorgaans 5-10 gelijktijdige verzendingen per gekoppeld account). Voor echt grootschalige marketingverzendingen (miljoenen per dag), combineer Unipile voor OAuth-gebaseerde transactionele verzendingen met een speciale ESP voor bulkcampagnes.
Voor lichtere gebruiksscenario's, concurrent.futures.ThreadPoolExecutor(max_workers=5) met de verzoekt library is een eenvoudigere aanpak die de Celery overhead vermijdt.
Ja. Maak een Celery-taak die roept requests.post() naar het Unipile-eindpunt. Celery-workers zijn standaard synchrone Python-processen, dus verzoekt werkt perfect. Gebruik Celery's ingebouwde autoretry_for=(requests.exceptions.HTTPError,) met max_pogingen=3 en standaard_herhaal_vertraging=5 voor automatisch opnieuw proberen bij tijdelijke fouten. Combineer met Idempotentie-sleutel headers om dubbele verzendingen bij herstarten van workers te voorkomen.
Heb je nog vragen? Ons team staat klaar om te helpen.