logo

Barong mailer

Mailer in the barong app is a deamon listening events from RabbitMQ, it renders emails using templates in the language set in user profile (if possible) and send emails.

This guide explains the basics of using mailer to manage events from rubykube Event API.

It is usually used by following components:

Read more about Peatio Event API. Read more about Barong Event API.

#Concepts

An Event is a message produced to message broker in RFC7515.

Events have the following structure:

{
  "payload": "string",
  "signatures": [
    {
      "header": {
        "kid":"string"
      },
      "protected":"string",
      "signature":"string"
    }
  ]
}

#Deep dive

By specification defined in RFC7515 we can build a JSON Web Token.

After parsing of prebuilt JWT, you will receive this payload with this structure.

{
  "iss": "string",
  "jti": "string",
  "iat": 1567777420,
  "exp": 1567777480,
  "event": {
    "record": {
      "user": {
        "uid": "string",
        "email": "string",
      },
      "language": "string",
    },
    "name": "string"
  }
}

Note: All events should be properly signed using RS256 private key.

Mailer validates the signature of each upcoming event.

Further, we will see that mailer user can work with this payload directly.

{
  "record": {
    "user": {
      "uid": "UID12345678",
      "email": "[email protected]"
    },
    "language": "EN"
  },
  "changes": {},
  "name": "string"
}

#Run

VariableDescriptionRequiredDefault
BARONG_EVENT_API_RABBITMQ_HOSTHost of RabbitMQ daemonnolocalhost
BARONG_EVENT_API_RABBITMQ_PORTPort of RabbitMQ daemonno5672
BARONG_EVENT_API_RABBITMQ_USERNAMERabbitMQ usernamenoguest
BARONG_EVENT_API_RABBITMQ_PASSWORDRabbitMQ passwordnoguest
BARONG_SMTP_PASSWORDPassword used for auth to SMTPyes
BARONG_SMTP_PORTPost of SMTP serverno25
BARONG_SMTP_HOSTHost of SMTP servernosmtp.sendgrid.net
BARONG_SMTP_USERUser used for auth to SMTPnoapikey
BARONG_SENDER_EMAILEmail address of mail senderyes
BARONG_SENDER_NAMEName of mail sendernoBarong
./bin/mailer --config=config/mailer.yml run

Mailer creates one queue and bind pre-defined exchanges to it.

#Configuration

Mailer is a flexible tool, you can cusomize alomost everything. Biggest part of customizations defined in mailer.yml, but you can also modify templates.

Each Event API provider uses own AMQP exchange and algorithm to sign payload.

exchanges:
  barong:
    name: barong.events.system
    signer: peatio

Using keychain algorithms and defined public keys for each provider mailer will validate the data.

keychain:
  barong:
    algorithm: RS256
    value: "public_key"

In events you may define any event type from Event API providers and prepare email template for it.

events:
  - name: Email Confirmation
    key: user.email.confirmation.token
    exchange: barong
    templates:
      EN:
        subject: Registration Confirmation
        template_path: email_confirmation.en.html.erb
      RU:
        subject: Подтверждение Регистрации
        template_path: email_confirmation.ru.html.erb

The simpliest mailer configuration will look like this one:

keychain:
  barong:
    algorithm: RS256
    value: "changeme"
  peatio:
    algorithm: RS256
    value: "changeme"

exchanges:
  barong:
    name: barong.events.system
    signer: barong

events:
  - name: Email Confirmation
    key: user.email.confirmation.token
    exchange: barong_system
    templates:
      en:
        subject: Registration Confirmation
        template_path: email_confirmation.en.html.erb
      ru:
        subject: Подтверждение Регистрации
        template_path: email_confirmation.ru.html.erb

#Templates

Mailer exposes few variables for usage inside the templates.

VariableDescription
@userUser related to this email
@recordCreated user up-to-date attributes.
@changesThe changed user attributes and their values

User

User with related profile.

Variable
uidUnique user id
emailUser email
roleUser role
levelUser KYC level
stateState of user's account
referral_idUID of referrer
profileInformation about KYC profile

Record

Record always containes UID and other attributes, that's why we can also expose user, by searching with unique user id.

Example:

record: {
  uid: "ID30DD0DD986",
  email: "[email protected]",
  role: "member",
  level: 1,
  otp: false,
  state: "pending",
  created_at: "2019-01-28T08:35:29Z",
  updated_at: "2019-01-28T08:35:29Z"
}

Changes

When entity changed, this will contain attributes before an udpate.

Example:

changes: {
  level: 0
}

Queues and exchanges schema

Mailer-Schema

How retries works

RabbitMQ Cluster is part of our infrastructure and the default queuing solution. RabbitMQ has Dead Letter Exchanges (DLX), which allows us to simulate message scheduling.

Steps to test the solution:

  1. Publish message to TargetQueue
  2. Consumer gets the message and tries to process it
  3. Process fails, consumer rejects the message
  4. Rabbit routes the message to RetryExchange
  5. Message moves to RetryQueue, sits for 2 minutes
  6. When message expires, it is resent to TargetExchange and routed to TargetQueue

Mailer-Retry