#Webhook processing

152 messages Β· Page 1 of 1 (latest)

vale shale
#

I am very much of a beginer and trying to follow django-anymail documentation:
https://anymail.dev/en/stable/quickstart/

Got to a point where I am succesfully sending emails using (sendiblue) and now trying to follow webhook documentation for tracking:
https://anymail.dev/en/stable/sending/tracking/#

I have sucesfully configured webhooks as per here:
https://anymail.dev/en/stable/installation/#webhooks-configuration

On my vercel app I see that I am being hit with successfully to my webhooks:

SEP 28 09:44:52.18
200
django-anymail.vercel.app
[POST] /anymail/sendinblue/tracking/
using Web Server Gateway Interface (WSGI) Message <202309280829.50870869121@smtp-relay.mailin.fr> to dz00nas@gmail.com opened
SEP 28 09:29:51.73
200
django-anymail.vercel.app
[POST] /anymail/sendinblue/tracking/
SEP 28 09:29:51.03
200
django-anymail.vercel.app
[POST] /anymail/sendinblue/tracking/

But now I do not understand how to process these, I tried the following:

  1. I created a new app called emailtracking
  2. created signals.py inside emailtracking folder
from anymail.signals import tracking
from django.dispatch import receiver

@receiver(tracking)  # add weak=False if inside some other function/class
def handle_bounce(sender, event, esp_name, **kwargs):
    if event.event_type == 'bounced':
        print("Message %s to %s bounced" % (
              event.message_id, event.recipient))

@receiver(tracking)  # add weak=False if inside some other function/class
def handle_bounce(sender, event, esp_name, **kwargs):
    if event.event_type == 'sent':
        print("Message %s to %s sent" % (
              event.message_id, event.recipient))

@receiver(tracking)  # add weak=False if inside some other function/class
def handle_bounce(sender, event, esp_name, **kwargs):
    if event.event_type == 'opened':
        print("Message %s to %s opened" % (
              event.message_id, event.recipient))
#
  1. inside emailtracking/app,py
from django.apps import AppConfig

class YourAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'emailtracking'

    def ready(self):
        import emailtracking.signals  # Import the signals file
#
  1. inside vercel_app/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'example',
    'anymail',
    'emailgenerator',
    'emailtracking'
]

#

but I am not getting any print messages in vercel logs or my local running version I think I lack some basic understanding here that is obvious

main pulsar
#

I'm not familiar with anymail, but could the problem be that you redefine the function?

>>> def foo(): print("hello")
... 
>>> def foo(): print("world")
... 
>>> def foo(): print("last one wins")
... 
>>> foo()
last one wins
#

You probably only want one of those def handle_bounce() with checks for different conditions within it...

#
@receiver(tracking)  # add weak=False if inside some other function/class
def handle_bounce(sender, event, esp_name, **kwargs):
    if event.event_type == 'bounced':
        print("Message %s to %s bounced" % (
              event.message_id, event.recipient))
    if event.event_type == 'sent':
        print("Message %s to %s sent" % (
              event.message_id, event.recipient))
    if event.event_type == 'opened':
        print("Message %s to %s opened" % (
              event.message_id, event.recipient))
vale shale
#

ill test now

#

@main pulsar where am I supposed to see the print? in the local terminal or on vercel? or both?

main pulsar
#

You should see it in Vercel, probably, though I am not familiar with it as I never deployed anything there...

vale shale
#

ok so that made no difference

#

I guess we could get rid of event.event_type == over all

#

and see if anything is getting triggered at all

main pulsar
#

You can just add a print() at the top of the function, before the ifs

vale shale
#

how could we fire a print command from there manually from that app so at least I could test if I can see that in vercel

#

so gonna try this

@receiver(tracking)  # add weak=False if inside some other function/class
def handle_bounce(sender, event, esp_name, **kwargs):
    print("testing")
    if event.event_type == 'bounced':
        print("Message %s to %s bounced" % (
              event.message_id, event.recipient))
    if event.event_type == 'sent':
        print("Message %s to %s sent" % (
              event.message_id, event.recipient))
    if event.event_type == 'opened':
        print("Message %s to %s opened" % (
              event.message_id, event.recipient))
main pulsar
#

Probably a good idea to rename the function too, since it handles different webhook events, not just bounced mail, but that's more of a stylistic issue than cause for concern.

vale shale
#

sure

#

is there any way I could do some sort of timed print?

#

so it just keeps firing from that app?

#

so I could rule out that the app is connected right?

#

just have to make sure I am not doing some basic beginer mistakes too

#

oh the testing print works

#

ok so it's the event type

#

I could just print the event and see whats happening inside of it right?

#

wooohooo

#

rubba ducka debugging is dank

main pulsar
#

Timed, not easily... you can put it before the function definition so it prints when the file is imported and the function is defined rather than called.

vale shale
#

alright ill keep that in mind if I doubt myself again

#

but it seems that I have done everything right

main pulsar
#

And yeah, I was gonna suggest you replace print("testing") with print(f"received event {event.event_type}") or something πŸ˜„

vale shale
#

I think event type does not exist at all

#

ill try printing the whole event

#

I feel that there will be something unfinished/not workign here with sendiblue

#

oh jesus

#

I need to stop calling it

#

sendiblue

#

django-anymail[sendiblue]

#

it is missing and n

#

sendinblue it should be

#

and I think I am basically missing packages

#

I discovered the missing n on webhook yesterday

#

too

#

so now we know

#

let me see what happens

#

do I need to do { } inside of print? that stringify's it?

#

if I just do plain print(event) I wont see it?

main pulsar
#

print(event) should work

vale shale
#

hmm but I cant read what is inside of it then

main pulsar
#

I just wrote an f-string...

vale shale
#

<anymail.signals.AnymailTrackingEvent object at 0x7f71e7a0da90>

#

I just get this

main pulsar
#

You can try print(str(event))

#

But depending on the __str__(self) method definition, it may not help much πŸ˜„

vale shale
#

hmm ok let me give it a try

#

same result
<anymail.signals.AnymailTrackingEvent object at 0x7f179a29d2e0>

#

let me just do the event.type then

main pulsar
#

Mess around with it until you get to the good stuff πŸ™‚

vale shale
#

ok delivered and queeud

main pulsar
#

print(dir(event))

vale shale
#

are the first two types

#

ill try dir thank you

main pulsar
#

Yeah, you don't handle those.

vale shale
#

wait

#

so if I have 2 prints in the same function they are merged into one console log?

#

SEP 28 10:54:57.98
200
django-anymail.vercel.app
[POST] /anymail/sendinblue/tracking/
opened Message <202309280952.34298647574@smtp-relay.mailin.fr> to dz00nas@gmail.com opened
SEP 28 10:54:31.26
200
django-anymail.vercel.app
[POST] /anymail/sendinblue/tracking/
delivered
SEP 28 10:54:29.24
200
django-anymail.vercel.app
[POST] /anymail/sendinblue/tracking/
queued
#

so I was getting opened before

#

because the first print

#

yeah somehow weirdly I think they got merged

#

thats sooooo weird

#

but ok

#

ok ok ok ok

#

so we are printing in the console

#

that is it I am all goo

#

good

#

and I always was good

#

it was just that few event types were not right

#

so now I just need to process these signals

#

and store them in my database

#

and badabim badabum

#

one quick question

#

so I was thinking actually

#

I am so used to firebase / angular

#

and I have seen django firebase integration floating around

#

that way this is just a backend service processing all this email stuff

#

and storing it into my firebase database

#

from there I feel like I am back at home

#

when it comes to frontend

#

or am I supposed to do all the templating in the django app?

main pulsar
#

Not entirely sure I understand...

#

You can not use Django's template system at all if you don't want to.

#

You can use Django-Rest-Framework or GraphQL to write APIs.

#

And have an SPA written in Angular, or Vue, or Svelte and consume the API.

vale shale
#

alternative to that is to use django templating

#

there is no way to substitute django templating with angulars right? you have to always do this creation of API and then consuming it in the frontend at that point

#

awww maaan now I gotta learn graphQL

#

this never stops LOL

main pulsar
#

Ehh... there are, but it sounded messy to me so I never bothered with it πŸ˜„

vale shale
#

ahh ok

#

yeah I think it would be messy too

#

the backend/frontend seperation sounds good

main pulsar
#

If you can build custom web components using angular, maybe you can use those...

vale shale
#

plus at that point the backends are isolated

#

you can have multiples

#

acting as services

#

I guess this is that microservice memery?

#

as in I can use same backend against multiple different frontends for that specific task

main pulsar
#
{% extends "base.html" %}
{% block content %}
<angular-component></angular-component>
{% endblock %}
vale shale
#

yikes

main pulsar
#

Unrelated to microservices. It's just a decoupled architecture.

vale shale
#

what is a microservice then?

main pulsar
#

Which is useful if you decide to write a native Android app in Kotlin to access the same API.

#

Usually extra back-end services running in different environments.

vale shale
#

oh yeah

#

because why the hell would you run a monolith like django as microservice I guess this is where smaller libraties like flask are used

main pulsar
#

If you look at e.g. youtube, when you upload a video, a few services start up.

#

One to transcode it to different resolutions, one to check for copyrighted audio, one to use ML/AI to generate subtitles, etc.

#

You can run multiple Django apps as microservices (though I guess they are not exactly micro πŸ˜„ ), or have microservices that work with Django, too.

vale shale
#

ok

#

MACROSERVICE

#

DJANGO EMAIL PROCCESING

#

MADE BY HEXAS

#

loololol

#

ok thank you theepicdev

#

have a nice day

main pulsar
#

You too πŸ™‚

#

I need more coffee first πŸ˜…

vale shale
#

sameeee

#

and a banana

#

for sugar

#

code monkey loves his bananas

main pulsar
#

Literally was thinking the same.

vale shale
#

ancient memes

#

I love it

main pulsar
#

I am a dinosaur in computing years

vale shale
#

I have been there

main pulsar
vale shale
#

garrys mod

main pulsar
#

I need to add it to the 404 page

vale shale
#

peanut butter jelly time

#

2008 youtube was wild

#

or maybe even 2006 not even sure anymore

vale shale
#

a true backend developer vision of a frontend for sure

#

now lets see paul allens card

#

Powering the Digital Revolution, Connecting Minds, Unleashing Possibilities! We are a full-service creative studio. Strategic collaboration is the key to our success. As a creative development agency, we excel in seamlessly combining different fields of expertise to deliver exceptional projects for our clients. Unlock Revenue Growth for Your Bus...

main pulsar
#

Sweet