Last active
May 25, 2021 09:28
-
-
Save TheRusskiy/cb4adca186e5a14dc2a99921b150ca04 to your computer and use it in GitHub Desktop.
Revisions
-
TheRusskiy revised this gist
May 25, 2021 . 4 changed files with 13 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,11 +3,15 @@ def new_blog_post(blog_post, subscriber) # by calling "store_message" we are saying that this # emails need to be saved in our database # for further tracking store_message( email_name: 'new_blog_post', entity: blog_post, user: subscriber ) mail( to: subscriber.email, subject: "New Post: #{blog_post.title}", # this param is required if you want Postmark to add a tracking pixel # and send you status updates track_opens: 'true' @@ -18,9 +22,11 @@ def new_blog_post(blog_post, subscriber) # email_name - some name we can later use for statistics # entity - any ActiveRecord model we want to associate the email with # user - user this email is sent to def store_message(email_name:, entity:, user: nil) self.metadata['email_name'] = email_name.to_s.truncate(80) self.metadata['entity_id'] = entity.id self.metadata['entity_type'] = entity.class.name self.metadata['user_id'] = user.id if user end end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -4,6 +4,7 @@ def change t.text :email_name, null: false t.text :message_id t.references :entity, polymorphic: true, index: true t.references :user, foreign_key: true, null: true, index: true t.integer :status, default: 0, null: false t.datetime :opened_at t.text :error This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -15,6 +15,7 @@ def self.delivered_email(m) message_id: m.message_id, entity_id: m.metadata['entity_id'], entity_type: m.metadata['entity_type'], user_id: m.metadata['user_id'], subject: m.subject ) end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,5 +1,6 @@ class SentEmail < ApplicationRecord belongs_to :entity, polymorphic: true belongs_to :user, optional: true enum status: { sent: 0, opened: 1, failed: 2 } validates_presence_of :email_name, :status validates_presence_of :message_id, unless: :failed? -
TheRusskiy revised this gist
May 25, 2021 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -7,7 +7,9 @@ def new_blog_post(blog_post, subscriber) mail( to: subscriber.email, subject: "New Post: #{blog_post.title}", # this param is required if you want Postmark to add a tracking pixel # and send you status updates track_opens: 'true' ) end -
TheRusskiy revised this gist
May 25, 2021 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -19,3 +19,5 @@ def self.delivered_email(m) ) end end ActionMailer::Base.register_observer(PostmarkMailObserver) -
TheRusskiy created this gist
May 25, 2021 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,24 @@ class ApplicationMailer < ActionMailer::Base def new_blog_post(blog_post, subscriber) # by calling "store_message" we are saying that this # emails need to be saved in our database # for further tracking store_message(email_name: 'new_blog_post', entity: blog_post) mail( to: subscriber.email, subject: "New Post: #{blog_post.title}", track_opens: 'true' ) end protected # email_name - some name we can later use for statistics # entity - any ActiveRecord model we want to associate the email with def store_message(email_name:, entity:) self.metadata['email_name'] = email_name.to_s.truncate(80) self.metadata['entity_id'] = entity.id self.metadata['entity_type'] = entity.class.name end end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,9 @@ class EmailBouncedService def self.call(message_id:, error_message:) sent_email = SentEmail.find_by_message_id(message_id) return unless sent_email sent_email.update!(error: error_message, status: 'failed') end end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,10 @@ class EmailOpenedService def self.call(message_id:, first_open:, opened_at:) return unless first_open sent_email = SentEmail.find_by_message_id(message_id) return unless sent_email sent_email.update!(error: nil, status: 'opened', opened_at: opened_at) end end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,17 @@ class CreateSentEmails < ActiveRecord::Migration[6.1] def change create_table :sent_emails do |t| t.text :email_name, null: false t.text :message_id t.references :entity, polymorphic: true, index: true t.integer :status, default: 0, null: false t.datetime :opened_at t.text :error t.timestamps t.index :email_name t.index :entity_id t.index :message_id end end end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,26 @@ class PostmarkController < ActionController::Base skip_before_action :verify_authenticity_token # we are going to secure this webhook endpoint by using basic auth, # when defining your webhook on Postmark you should set it as # https://<username>:<password>@example.com/postmark_opened # https://<username>:<password>@example.com/postmark_bounced # TODO: use real credentials for basic auth http_basic_authenticate_with name: "SECRET_NAME", password: "SECRET_PASSWORD" def email_opened EmailOpenedService.call( message_id: params[:MessageID], first_open: params[:FirstOpen], opened_at: params[:ReceivedAt] ) render json: { status: 201 } end def email_bounced EmailBouncedService.call( message_id: params[:MessageID], error_message: params[:Description] ) render json: { status: 201 } end end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,21 @@ # place this file in config/initializers class PostmarkMailObserver def self.delivered_email(m) # only create a record if API has accepted the message return unless m.delivered? # as a part of API we are going to assume that # an email should be saved if "email_name" is set return unless m.metadata['email_name'].present? SentEmail.create( email_name: m.metadata['email_name'], status: 'sent', message_id: m.message_id, entity_id: m.metadata['entity_id'], entity_type: m.metadata['entity_type'], subject: m.subject ) end end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,4 @@ Rails.application.routes.draw do post 'postmark_opened', to: 'postmark#email_opened' post 'postmark_bounced', to: 'postmark#email_bounced' end This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,6 @@ class SentEmail < ApplicationRecord belongs_to :entity, polymorphic: true enum status: { sent: 0, opened: 1, failed: 2 } validates_presence_of :email_name, :status validates_presence_of :message_id, unless: :failed? end