Skip to main content

How to send e-mails using Postmark and Python

  • Register for Mailgun (free trial, up to 5 recipients)
  • Under "Sending", select the sandbox domain
  • Enter a new "authorized recipient" and then confirm it by clicking the button on the e-mail you've received.
  • Copy the "Python" code snippet which looks like this:
def send_simple_message():
return requests.post(
"https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
auth=("api", "YOUR_API_KEY"),
data={"from": "Excited User <mailgun@YOUR_DOMAIN_NAME>",
"to": ["bar@example.com", "YOU@YOUR_DOMAIN_NAME"],
"subject": "Hello",
"text": "Testing some Mailgun awesomness!"})
  • We will need this in a few moments!
DOMAIN = "sandbox723b0599ff8148a08a38f9df9cfaf5d9.mailgun.org"
def send_simple_message(to, subject, body):
return requests.post(
f"https://api.mailgun.net/v3/{DOMAIN}/messages",
auth=("api", os.getenv("MAILGUN_API_KEY"),
data={"from": f"Your Name <mailgun@{DOMAIN}>",
"to": [to],
"subject": subject,
"text": body})

Make sure to have this in your .env file:

POSTMARK_SERVER_API_TOKEN="751756815-5617a-158b98-bgb8a879858"
  • Next we will send an e-mail to the user when they register.
  • First let's add an e-mail column to our user model
+    email = db.Column(db.String, unique=True, nullable=False)
  • Then run the migration as we've already learned.
flask db migrate
flask db upgrade # make sure this is using the local dev database

Make the e-mail required through the schemas by creating a UserRegisterSchema:

class UserSchema(Schema):
id = fields.Int(dump_only=True)
username = fields.Str(required=True)
password = fields.Str(required=True, load_only=True)


class UserRegisterSchema(UserSchema):
email = fields.Str(required=True)

And then in the User resource:

from schemas import UserSchema, UserRegisterSchema

...

@blp.route("/register")
class UserRegister(MethodView):
@blp.arguments(UserRegisterSchema)
def post(self, user_data):
...

user = UserModel(
username=user_data["username"],
email=user_data["email"],
password=pbkdf2_sha256.hash(user_data["password"]),
)

Now when a user registers, we can send an e-mail:

import os
import requests

...

DOMAIN = "sandbox723b0599ff8148a08a38f9df9cfaf5d9.mailgun.org"
def send_simple_message(to, subject, body):
return requests.post(
f"https://api.mailgun.net/v3/{DOMAIN}/messages",
auth=("api", os.getenv("MAILGUN_API_KEY")),
data={"from": f"Your Name <mailgun@{DOMAIN}>",
"to": [to],
"subject": subject,
"text": body}
)

...

@blp.route("/register")
class UserRegister(MethodView):
@blp.arguments(UserRegisterSchema)
def post(self, user_data):
if UserModel.query.filter(UserModel.username == user_data["username"]).first():
abort(409, message="A user with that username already exists.")

user = UserModel(
username=user_data["username"],
email=user_data["email"],
password=pbkdf2_sha256.hash(user_data["password"]),
)
db.session.add(user)
db.session.commit()

send_simple_message(
to=user.email,
subject="Successfully signed up",
body=f"Hi {user.username}! You have successfully signed up to the Stores REST API."
)

return {"message": "User created successfully."}, 201

We will also want to add some error handling on the unique e-mail column:

from sqlalchemy import or_

...

@blp.route("/register")
class UserRegister(MethodView):
@blp.arguments(UserRegisterSchema)
def post(self, user_data):
if UserModel.query.filter(
or_(
UserModel.username == user_data["username"],
UserModel.email == user_data["email"]
)
).first():
abort(409, message="A user with that username or email already exists.")