This is a web app which allows multiple users to contribute articles to a school newsletter.
In this guide we will use the following placeholders:
<your-email-domain>
- the domain of your user email addresses, e.g.example.com
<your-newsletter-domain>
- the domain where your newsletter static website will be available via the Azure CDN, e.g.newsletter.example.com
<your-newsletter-builder-domain>
- the domain where the newsletter builder app will be hosted, e.g.build.newsletter.example.com
Here are the steps:
-
Create a general purpose v2 storage account in Microsoft Azure.
- Add a private container:
photos
- Add tables:
articles
,events
,newsletters
,recipients
,users
- The
users
table needs an initial entry, and this must be a valid user on your Azure tenant:- PartitionKey -
<your-email-domain>
- RowKey -
<username>
- IsEditor -
true
- FirstName -
<your-first-name>
- DisplayName -
<your-title-and-surname>
- PartitionKey -
- Enable static website hosting, and set the index document to
index.html
and the error document to404.html
. This will create a$web
blob container, which will be the root of the public-facing newsletter website. - Customise the contents of the
StaticWebsite
folder in this repository, for example replacing placeholders with their appropriate values. Then upload to the$web
blob container. Also uploadlogo.jpg
(250x250px),logo-hd.jpg
(1200x1200px),favicon.ico
, andicon-192x192.png
. - Enable CORS for blob
GET
requests fromhttps://<your-newsletter-builder-domain>
.
- Add a private container:
-
Create an Azure CDN endpoint with the static website as its origin, and a custom domain set to
https://<your-newsletter-domain>
. Enable compression. Add the following rules:- If request protocol =
HTTP
then URL redirect Found (302), HTTPS - If URL file extension =
jpg
,png
,pdf
,css
, orjs
(lowercase) then modify response header: overwriteCache-Control
max-age=31536000
, and then cache expiration: override365
days. - If URL file extension =
json
,html
, ortxt
(lowercase) then modify response header: overwriteCache-Control
no-cache
, and then cache expiration: bypass cache. - If URL path does not contain
.
then modify response header: overwriteCache-Control
no-cache
, and then cache expiration: bypass cache.
- If request protocol =
-
Create an Azure app registration.
- Name -
Newsletter Builder
- Redirect URI -
https://<your-newsletter-builder-domain>/signin-oidc
- Implicit grant -
ID tokens
- Supported account types -
Accounts in this organizational directory only
- API permissions -
Microsoft Graph - User.Read
- Token configuration - add optional claim of type
ID
:upn
- Name -
-
Create an Azure OpenAI Service GPT-4 deployment.
-
Create a Postmark server.
-
Create an Azure App Service web app, and configure the following settings:
NewsletterEditorUrl
- the URL of the newsletter editor (https://<your-newsletter-builder-domain>
)Organisations__0__Name
- the name of your organisationOrganisations__0__Domain
- the domain for your organisation (<your-email-domain>
)Organisations__0__NewsletterUrl
- the URL of the published newsletter (https://<your-newsletter-domain>
)Organisations__0__Address
- the address of your organisationOrganisations__0__Footer
- the footer text to include in emailsOrganisations__0__BannedWords
- a JSON array of words which are not allowed in articlesOrganisations__0__PhotoConsentUrl
- the URL of the photo consent spreadsheetOrganisations__0__UnlistedArticles__0
- an article name which should not be listed on the index page, for example a regular standing item (subsequent unlisted articles can be set up by adding additional items with incrementing indices)Organisations__0__FromEmail
- the email address from which newsletters and reminders will be sentOrganisations__0__QualityAssuranceEmail
- the email address to which quality assurance requests will be sentOrganisations__0__SocialMediaEmail
- the email address to receive requests to share the newsletter on social mediaOrganisations__0__ReminderReplyTo
- the reply-to address for remindersOrganisations__0__TwitterHandle
- the Twitter handle of your organisation, starting with an @ symbolOrganisations__0__DefaultDeadlineDaysBeforePublish
- the default number of days before the publish date that articles are dueOrganisations__0__AzureStorageStaticWebsiteAccountName
- the account name of the storage account where the newsletter static website is hostedOrganisations__0__AzureStorageStaticWebsiteAccountKey
- the account key of the storage account where the newsletter static website is hostedOrganisations__0__Reminders__0__DaysBeforeDeadline
- the number of days before the publish date to send the first reminder (subsequent reminders can be set up by adding additional items with incrementing indices)Organisations__0__Reminders__0__Subject
- the subject of the reminder emailOrganisations__0__Reminders__0__Message
- the message to include in the reminder emailAzure__ClientId
- the client ID of your Azure app registrationAzure__TenantId
- your Azure tenant IDAzure__StorageAccountName
- the name of your Azure Storage accountAzure__StorageAccountKey
- the key for your Azure Storage accountOpenAI__Model
- the name of the OpenAI model to useOpenAI__Key
- your OpenAI API keyPostmarkServerToken
- the token for your Postmark serverAutomationApiKey
- a secret GUID which is used to authenticate requests to the automation API
-
Deploy to the App Service web app you created.
-
Create scheduled tasks to call the
/api/automate/emailreminders/<your-email-domain>/<n>
endpoints for each reminder you configured, where<n>
is the index of the reminder.