@bigbinary/neeto-email-delivery-frontend
v1.0.32
Published
This repo is for implementing custom email delivery functionality for the Neeto platform.
Readme
neeto-email-delivery-nano
The neeto-email-delivery-nano acts as the source of truth for the new nano's
structure, configs, data etc..
Contents
Development with Host Application
Engine
Installation
Add this line to your application's Gemfile:
source "NEETO_GEM_SERVER_URL" do # ..existing gems gem 'neeto-email-delivery-engine' endAnd then execute:
bundle installAdd this line to your application's
config/routes.rbfilemount NeetoEmailDeliveryEngine::Engine, at: "/neeto_email_delivery"Add required migrations in the
db/migratefolder. Run the following commands to copy the migrations from the engine to the host application.bundle exec rails neeto_email_delivery_engine:install:migrations bundle exec rails db:migrateInclude NeetoEmailDeliveryEngine::DeliveryMethodSelector in the host's application_mailer.rb
class ApplicationMailer < NeetoCommonsBackend::ApplicationMailer
+ include NeetoEmailDeliveryEngine::DeliveryMethodSelector
# ...
end
6. Include NeetoEmailDeliveryEngine::HasEmailIntegrations in the host's owner model and override the `email_delivery_redirect_url` and `get_organization_id` method
```diff
class Form < ApplicationRecord
# ...
+ include NeetoEmailDeliveryEngine::HasEmailIntegrations
# ...
def email_delivery_redirect_url
# "/admin/..."
end
def get_organization_id
# organization_id
end
end- Add
config/initializers/neeto_email_delivery_engine.rband add the owner class. Example:
NeetoEmailDeliveryEngine.owner_class = "Form"- Override the
load_ownerprivate method for the base controller.
# app/overrides/controllers/neeto_email_delivery_engine/base_controller_override.rb
NeetoEmailDeliveryEngine::Api::V1::BaseController.class_eval do
private
def load_owner
# @owner = current_user
# OR
# @owner = @organization.forms.find(params[:owner_id])
end
end- Override the
send_disconnection_emailprivate method -
- app/overrides/services/neeto_email_delivery_engine/base_email_service_override.rb
NeetoEmailDeliveryEngine::BaseEmailService.class_eval do
private
def send_disconnection_email(integrable, organization_id, type)
# Call your mailer logic
# type: gmail, outlook, smtp
# DisconnectionMailer
# .with(organization_id: organization_id)
# .send_email(user: integrable, type:)
# .deliver_later
end
end- Add mailgun ingress config in application.rb
config.action_mailbox.ingress = :mailgunAdd
:gmailand:outlookto omniauth_providers in config/initializers/extend_user_omniauth.rb.The following env variables need to be added to the host application.
GOOGLE_OAUTH_CLIENT_ID
GOOGLE_OAUTH_CLIENT_SECRET
MICROSOFT_OAUTH_CLIENT_ID
MICROSOFT_OAUTH_CLIENT_SECRET
SPARKPOST_SENDING_DOMAINS_KEY
## The following are needed, but they should already be present in the host application. So ensure that they are present.
APP_LOCAL_TO_INTERNET_PROXY_URL
CONNECT_PRIVATE_KEY
CONNECT_PUBLIC_KEY
MAILGUN_INGRESS_SIGNING_KEY (needed for our custom logic to verify the Outlook account.)- In secrets.yml add
sparkpost:
sending_domains_key: <%= ENV['SPARKPOST_SENDING_DOMAINS_KEY'] %>
sending_domains_user_name: SMTP_Injection
sending_domains_address: smtp.sparkpostmail.comEnsure that the domain
<app-name>email.com(production) and<app-name>email.net(staging) is correctly setup in Mailgun to accept incoming emails. Example: For NeetoForm it would be neetoformemail.com (production) and neetoformemail.net (staging).Add the following to ApplicationMailbox
routing /neetoemaildelivery/i => "neeto_email_delivery_engine/inbound"- Override
skip_rate_limits?forNeetoRateLimitEngine::MailDeliveryJobto skip rate limiting if user has their SMTP integration configured.
# app/overrides/neeto_rate_limit_engine/jobs/mail_delivery_job_override.rb
NeetoRateLimitEngine::MailDeliveryJob.class_eval do
private
def skip_rate_limits?
is_smtp_email_job?
end
def is_smtp_email_job?
return false if params[:delivery_account].blank?
account_klass, account_id = params[:delivery_account].values_at(:klass, :id)
delivery_account = account_klass.constantize.find_by(id: account_id)
delivery_account.present? &&
delivery_account.is_a?(NeetoEmailDeliveryEngine::SmtpAccount) &&
delivery_account.active?
end
endFrontend package
Installation
Add the
neeto-email-delivery-frontendpackage to thepackage.jsonyarn add @bigbinary/neeto-email-delivery-frontend
Instructions for development
Check the Frontend package development guide for step-by-step instructions to develop the frontend package.
Usage
Exported components
EmailDeliveryScreen
| Prop | Type | Description |
| ----------------------- | ----------- | ------------------------------------------------------------ |
| canManageIntegrations | boolean | Authorization/permission check for this feature. |
| ownerId | uuid/string | ID of the owner record. |
| indexRoute | string | Index route for the email delivery page. |
| ownDomainSetupRoute | string | Nested route for the SparkPost "Own Domain" setup component. |
| ownDomainVerifyRoute | string | Nested route for the SparkPost "Verify Domain" component. |
SparkpostDomainSetup
| Prop | Type | Description |
| ----------------------- | ----------- | ---------------------------------------------------------------------------- |
| canManageIntegrations | boolean | Authorization/permission check for this feature. |
| ownerId | uuid/string | ID of the owner record. |
| alreadyVerifiedRoute | string | Route for the "already verified" page; typically the email delivery index. |
| verifyRoute | string | Route for the verification page that shows DKIM records. |
| onCancelRoute | string | Route to redirect users on cancellation; typically the email delivery index. |
SparkpostDomainVerify
| Prop | Type | Description |
| ------------------------- | ----------- | ------------------------------------------------ |
| canManageIntegrations | boolean | Authorization/permission check for this feature. |
| ownerId | uuid/string | ID of the owner record. |
| emailDeliveryIndexRoute | string | Index route for the email delivery page. |
Business logic for sparkpost verification
If the domain is not created on Sparkpost
- Create the domain in sparkpost
- Present the DKIM values to the user and ask the user to add it to their DNS
- Present a verify button.
- On verification, we make an API call to NeetoTower with domain and current organization.guid as parameters.
If the domain is created on Sparkpost but not verified, then
- Present the DKIM values to the user and ask the user to add it to their DNS
- Present a verify button.
- On verification, we make an API call to NeetoTower with domain and current organization.guid as parameters.
If the domain is created on Sparkpost and verified, then (New flow)
- Make a call to NeetoTower to check if the domain + current organization_guid record is present.
- If the response from NeetoTower says the domain + current organization_guid exist, then just approve the domain automatically.
- If the response from NeetoTower says the domain + current organization_guid
doesn't exist, then
- Show a custom TXT value and ask the user to add it to their DNS.
- Present a verify button which checks the above TXT value.
- On verification, we make an API call to NeetoTower with domain and current organization.guid as parameters.
Sparkpost Domain statuses
- pending - The default status when the sparkpost domain is created.
- sp_dkim_verified - The domain's DKIM record has been verified in Sparkpost.
- sp_dkim_unverified - The domain's DKIM record is yet is not verified in Sparkpost.
- failed - Failure state when any of the Sparkpost API's for verification fail.
- txt_unverified - This is for the case when a domain has been verified for a different organization. We store the domain+organization mapping in NeetoTower. If the domain+organization mapping is not present in NeetoTower but the domain is verified on Sparkpost, then we use this state to indicate that the domain needs further verification via validating TXT records. If the domain+organization mapping is already present in NeetoTower, then we directly mark the domain as active.
- active - The final state. If active, then we will allow sending emails via this domain.
Outlook integration flow
Ensure that MAILGUN_INGRESS_SIGNING_KEY environment variable is set in the
host application. This is needed for the verification of the Outlook account.
Connect Outlook from UI
- User clicks the "Connect Outlook" action in the host application.
- The engine redirects the user to Microsoft OAuth using
User.Read,Mail.Send, andoffline_accessscopes so that we can send emails and refresh tokens without re‑auth.
Store Outlook account and send verification email
- After a successful OAuth callback,
NeetoEmailDeliveryEngine::Integrations::Outlook::ConnectServicecreates or updates anOutlookAccountand sets its status toinactive. - The service generates a
test_email_token, persists it in the account metadata (along with timestamp and subject), and sends a test email viaNeetoEmailDeliveryEngine::Outlook::SendEmailServiceusing the Microsoft GraphsendMailAPI to a generated verification address likeoutlook.neetoemaildelivery@<application_name>email.(com|net).
- After a successful OAuth callback,
Inbound verification handling
- Incoming emails to the verification address are processed by
NeetoEmailDeliveryEngine::InboundMailbox. - The mailbox identifies Outlook verification emails by recipient and
subject, extracts the
test_email_tokenfrom the subject, and finds the correspondingOutlookAccount. - If the email is from a legitimate user mailbox and the account is not
already active, the mailbox updates the account status to
active. If the sender looks like an Outlook shadow account (e.g.[email protected]), the mailbox flags the account asshadow_accountand marks it asforbiddeninstead of activating it.
- Incoming emails to the verification address are processed by
Disconnection emails
In case the email delivery fails using the Gmail/Outlook integrations, we disconnect the integration and send out an email. To customize the email, the host application needs to add an override so that they are in control of the mailers.
Override the base_email_service.rb as mentioned above in installation step 9.
## Instructions for Publishing
Consult the
[building and releasing packages](https://neeto-engineering.neetokb.com/articles/building-and-releasing-packages)
guide for details on how to publish..