School Helpdesk is a free, open-source web application designed to streamline communication between parents/carers and staff.
Bring your own Postmark account and deploy to Microsoft Azure.
- A clean, professional ticketing interface
- Email-based ticket submission for verified parents
- Automatic tagging of parent and student details
- Ticket assignment to specific staff
- Powerful search to quickly find previous tickets
- AI-assisted drafting to support faster, more consistent responses
- Automated notifications and follow-up reminders
- Customisable email templates
- Role-based access control for managers and staff
- Fully responsive design for desktop, tablet, and mobile use
- Microsoft 365 single sign-on for secure and convenient access
You will need an Azure subscription, permission to manage Entra app registrations, and administrative access to your school's DNS and Microsoft 365 or Google Workspace email routing. Azure hosting, storage, AI usage, and Postmark incur charges.
-
Create a Postmark Pro account.
- Add a sender signature for your school's email domain and verify it using DNS
- Add a server called
Helpdesk
-
Create a general purpose v2 storage account in Microsoft Azure, with account key access enabled, and within it create:
- Blob containers:
config,messages, andattachments - Queue:
emails - Table:
tickets
Keep all blob containers private.
- Blob containers:
-
Within the
configblob container:-
Upload a blank file
keys.xml. Generate a SAS URL for this file with read/write permissions and a distant expiry. This will be used to store the application's data protection keys so that auth cookies persist across app restarts. -
Upload a file
holidays.csvwith the following headers and populate it with your school's holiday dates inyyyy-MM-ddformat. The start and end dates are inclusive. Reminder emails will not be sent to staff during holidays.Start,End
-
Upload a file
students.csvwith the following headers and populate it with all students in your school. Where a student has more than one parent, repeat the student details across multiple rows. To correctly represent accented characters in student names, save the file in 'CSV UTF-8' format.Id,FirstName,LastName,TutorGroup,Relationship,ParentTitle,ParentFirstName,ParentLastName,ParentEmailAddress,ParentPhoneNumber
-
Upload a file
staff.csvwith the following headers and populate it with all staff who should have access, including administrators. EachEmailmust be unique and match the staff member's Entra user principal name (UPN), which may differ from their email address.Id,Email,Title,FirstName,LastName
-
Upload a file
blocklist.txtcontaining one email address or domain per line that should be blocked from contacting the helpdesk. Emails from these addresses will be ignored with no bounce message sent. This is useful for blocking spam. Registered parents cannot be blocked. You can start by using a blank file. -
Upload
template.htmlandtemplate.txttemplates to use for all outgoing emails. There are sample files in the examples folder. Replace the school details in both files. Use the token{{BODY}}as a placeholder for the email body.
-
-
Create a Microsoft Foundry project and deploy an OpenAI reasoning model (e.g.
gpt-5.6-sol). Record the Azure OpenAI resource's base endpoint, API key, and deployment name. -
Create an Azure App Service web app.
- Publish mode - Container
- Operating system - Linux
- Image source - Other container registries
- Container name -
main - Access type - Public
- Registry server URL -
https://index.docker.io - Image and tag -
jamesgurung/school-helpdesk:latest - Port - 8080
- Startup command: (blank)
- Always On - enabled, using a plan that supports it
- HTTPS Only - enabled
- Instance count - 1; do not enable scale-out
Ticket numbering and caches are held in application memory, so multiple instances are not supported. Reminders run at 07:30 UK time on weekdays outside the configured holidays and require the app to remain running.
-
Configure a custom domain for the web app, e.g.
helpdesk.example.sch.uk.- Add the required DNS records and bind the domain to the App Service
- Configure a TLS certificate and HTTPS binding for the domain
- Use this hostname for
AppWebsite, the Entra redirect URI, and the Postmark webhook
-
Create an Azure app registration.
- Name -
School Helpdesk - Platform - Web
- Redirect URI -
https://<app-website-domain>/signin-oidc - Supported account types - Accounts in this organizational directory only
- Token configuration - add an optional claim of type ID:
upn - Certificates & secrets - create a client secret and record its value, not its ID
Record the application (client) ID and directory (tenant) ID. The app uses authorization code flow; implicit grants and Microsoft Graph permissions are not required.
- Name -
-
Configure the application settings as described below. Either supply them directly as App Service environment variables or use Azure App Configuration.
If using Azure App Configuration, create a store and supply one of the following as an App Service environment variable:
AppConfigurationEndpoint- Azure App Configuration endpoint. Enable the App Service's system-assigned managed identity and grant it the App Configuration Data Reader role.ConnectionStrings__AppConfiguration- Azure App Configuration connection string (ConnectionStrings:AppConfigurationin JSON configuration).
For direct environment variables, use the names below without a prefix, e.g.
SchoolName. In Azure App Configuration, useShared:*orSchoolHelpdesk:*keys with no label, e.g.SchoolHelpdesk:SchoolName. Restart the app after changing settings in the store.Include at least one administrator. All addresses in
Admins,Managers, andDispatchersmust also appear instaff.csv. Administrators inherit manager permissions; managers inherit dispatcher permissions. Other staff can access their assigned tickets.Admins- a comma-separated list of admin email addresses; admins have full administrative accessAIFoundryApiKey- the API key for the Azure OpenAI resource hosting your deploymentAIFoundryDeployment- the name of the deployed OpenAI model that you would like to useAIFoundryEndpoint- the resource's base endpoint, e.g.https://<resource>.cognitiveservices.azure.com/; the app appends/openai/v1/AppWebsite- the host name where this app will be hosted, e.g.example.com, without a scheme or pathDataProtectionBlobUri- the SAS URL for the keys file you created earlierDebugEmail- redirects outgoing emails to this address whenever set, including in production; omit for normal operation (required for Debug builds)Dispatchers- a comma-separated list of dispatcher email addresses; dispatchers can create tickets assigned to staff, but reassigning existing tickets requires manager permissionsForwardingProvider- the provider that forwards inbound helpdesk email; must beMicrosoftorGoogleHelpdeskEmail- the email address that will be used to send and receive helpdesk ticketsManagers- a comma-separated list of manager email addresses; managers can create, view, and edit all ticketsMicrosoftClientId- the client ID of your Microsoft Entra app registrationMicrosoftClientSecret- the client secret of your Microsoft Entra app registrationMicrosoftTenantId- your Microsoft Entra tenant IDNotifyFirstManager- set totrueto notify the first email address inManagersof new tickets submitted by email; requires a nonempty manager list with its first entry instaff.csv(defaults tofalse)PostmarkInboundAuthKey- a secret UUID of your choice, used to verify that incoming emails are from PostmarkPostmarkServerToken- the token for your Postmark serverSchoolName- the name of your schoolStorageAccountKey- the key for your Azure Storage accountStorageAccountName- the name of your Azure Storage accountSyncApiKey- the secret key to use if you update thestudents.csvandstaff.csvfiles with an automated script (optional)
-
Configure your Postmark server's Default Inbound Stream settings:
- Set the webhook to
https://<app-website-domain>/inbound?auth=<authkey>, using the same secret asPostmarkInboundAuthKey - In Exchange or Google Workspace, route mail for
HelpdeskEmailto the Postmark inbound address, preserving the original sender and authentication headers; allow external forwarding for this address where required - Set
ForwardingProviderto match your email provider and ensure Postmark can send asHelpdeskEmailusing the server'soutboundmessage stream
- Set the webhook to
-
Verify setup before going live:
- Sign in as an administrator and check a regular staff account's access
- Send from an address in
students.csv, assign the resulting ticket, and send a staff response - Reply as the parent and confirm it updates the same ticket; test attachments and an AI suggestion
- Check an unregistered sender receives a rejection and confirm scheduled reminders are delivered
For startup failures, inspect App Service container logs and check required settings, storage access, and CSV formatting. For login failures, check the redirect URI,
upnclaim, andstaff.csv. For missing email, check routing, Postmark delivery/webhook records, and the sender verification rules below; a successful webhook response alone does not confirm ticket creation.
- After replacing CSVs, templates, or the blocklist in
config, restart the app or visit/api/refreshwhile signed in as an administrator. This reloads blob configuration, not application settings. - To automate staff/student updates, send
PUT /api/userswith anX-Api-Keyheader matchingSyncApiKeyand a multipart form containing both files, namedstaffandstudents. A successful upload reloads the data and returns HTTP 204. - Administrators can download a ZIP export from
/backup. It excludeskeys.xml, queues, and application settings; maintain separate backups of these as needed and a tested restoration procedure. There is no built-in restore endpoint. - Renew the Entra client secret and data-protection SAS before expiry, updating the corresponding settings. Preserve
keys.xmlwhen updating the application. - For upgrades, record the current container image digest, deploy the new image, and repeat the setup checks. The
latesttag can change; retain the previous digest for rollback.
The inbound relay chain is trusted as follows:
- School email server → Postmark: the Postmark inbound address is secret.
- Postmark → helpdesk app: the webhook
authvalue is secret.
When an email is received, the helpdesk app verifies the sender in the following order:
- Verify the webhook. Require the webhook
authvalue to matchPostmarkInboundAuthKey. - Verify the forwarding relay. Require the relay to pass SPF.
- Reject spam. Check Postmark's
X-Spam-Statusheader, if present, and reject messages marked as spam. - Verify the original sender. Require at least one of the following checks to pass:
- Postmark's
X-Spam-Testsheader containsDKIM_VALID_AU. - For schools using Microsoft email servers, the first
Authentication-Resultsheader contains eithercompauth=passordmarc=pass. - For schools using Google email servers, the first
Authentication-Resultsheader containsdmarc=pass, or containsdkim=passorspf=passwith the authenticatedheader.d/header.iorsmtp.mailfromdomain exactly matching the domain in theFromaddress.
- Postmark's
- Reject automated replies. Reject messages whose
Auto-Submittedheader is present and has any value other thanno. Also reject messages with a subject beginningAutomatic reply:. - Require a registered parent address. Create tickets only when the sender address belongs to a registered parent. At this stage only, unknown addresses receive an automated rejection reply.
If you have a question or feature request, please open an issue.
To contribute improvements to this project, or to adapt the code for the specific needs of your school, you are welcome to fork the repository.
Pull requests are welcome; please open an issue first to discuss.
