Remote Work Tools

Shared Inbox Setup for Remote Agency Client Support Emails

Configure a shared inbox for client support by using a platform like Front or Gmail shared inbox, assigning ownership for each email thread, and setting up SLAs to ensure timely responses across time zones. Shared inboxes prevent emails from falling through cracks when team members are unavailable.

This guide covers practical approaches to setting up shared inboxes specifically for remote agencies handling client support. You’ll find configuration examples, automation patterns, and decision criteria for choosing the right setup for your team.

The Problem with Basic Shared Email

Traditional shared email accounts create several issues for remote teams:

A proper shared inbox solution addresses these by providing ticket ownership, audit trails, and workflow automation.

Option 1: Google Groups with Shared Labels

The simplest approach uses Google Groups with label-based routing. This works well for teams already in the Google Workspace ecosystem.

Initial Configuration

Create a Google Group for your support inbox:

# Using Google Admin SDK (gcloud CLI)
gcloud alpha groups create support@youragency.com \
  --domain=youragency.com \
  --display-name="Client Support" \
  --description="Primary client support inbox"

Add team members and set up email routing. In Google Admin, configure the group to accept emails from external senders and forward them to all members or use the “Who can post” settings to restrict to members only.

Label-Based Workflow

Create labels for different client categories or ticket stages:

├── Client Support (root)
│   ├── New
│   ├── In Progress
│   ├── Waiting on Client
│   └── Escalated

Team members manually apply labels as they work tickets. This requires discipline but needs no additional tooling.

Option 2: IMAP + Custom Scripting

For teams wanting more control, set up a dedicated mail server with IMAP access and build custom automation. This approach gives you full data ownership and unlimited customization.

Postfix + Dovecot Setup

A basic Postfix configuration for a shared inbox:

# /etc/postfix/main.cf
virtual_alias_domains = youragency.com
virtual_alias_maps = hash:/etc/postfix/virtual
virtual_mailbox_domains = hash:/etc/postfix/vmail_domains
virtual_mailbox_maps = hash:/etc/postfix/vmail_users
virtual_mailbox_base = /var/mail/vhosts
# /etc/postfix/virtual
support@youragency.com support@youragency.com
@youragency.com support@youragency.com
# /etc/postfix/vmail_users
support@youragency.com:{PLAIN}hash_password_here:1000:1000::/var/mail/vhosts/youragency.com/support

Dovecot handles IMAP access:

# /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:~/Maildir
mail_privileged_group = mail

Ticket Extraction Script

Extract emails into a ticket system using a Python script:

#!/usr/bin/env python3
import imaplib
import email
from email.policy import default
import json
from datetime import datetime

def fetch_tickets(host, user, password, mailbox='INBOX'):
    """Fetch emails and structure as tickets."""
    mail = imaplib.IMAP4_SSL(host)
    mail.login(user, password)
    mail.select(mailbox)

    result, data = mail.search(None, 'ALL')
    ticket_ids = data[0].split()

    tickets = []
    for tid in ticket_ids[-50:]:  # Last 50 emails
        result, msg_data = mail.fetch(tid, '(RFC822)')
        raw_email = msg_data[0][1]
        msg = email.message_from_bytes(raw_email, policy=default)

        ticket = {
            'id': tid.decode(),
            'subject': msg['subject'],
            'from': msg['from'],
            'date': msg['date'],
            'body': get_body(msg),
            'headers': dict(msg.items())
        }
        tickets.append(ticket)

    mail.logout()
    return tickets

def get_body(msg):
    """Extract plain text body from email."""
    if msg.is_multipart():
        for part in msg.walk():
            if part.get_content_type() == 'text/plain':
                return part.get_content()
    return msg.get_content()

if __name__ == '__main__':
    with open('config.json') as f:
        config = json.load(f)

    tickets = fetch_tickets(
        config['imap_host'],
        config['imap_user'],
        config['imap_password']
    )

    for ticket in tickets:
        print(f"{ticket['id']}: {ticket['subject']}")

Option 3: Dedicated Support Platform Integration

For agencies handling significant support volume, integrating with platforms like HelpScout, Front, or Zendesk provides built-in workflows.

HelpScout API Example

// Node.js script to sync tickets to HelpScout
const axios = require('axios');

const HELPSCOUT_API = 'https://api.helpscout.net/v2';
const MAILBOX_ID = 'your-mailbox-id';

async function fetchConversations() {
  const response = await axios.get(
    `${HELPSCOUT_API}/mailboxes/${MAILBOX_ID}/conversations`,
    {
      params: {
        status: 'open',
        sort: 'modifiedAt',
        order: 'desc'
      },
      headers: {
        'Authorization': `Bearer ${process.env.HELPSCOUT_TOKEN}`
      }
    }
  );

  return response.data.conversations;
}

async function assignToAgent(conversationId, agentId) {
  await axios.patch(
    `${HELPSCOUT_API}/conversations/${conversationId}`,
    { assignee: { id: agentId } },
    {
      headers: {
        'Authorization': `Bearer ${process.env.HELPSCOUT_TOKEN}`,
        'Content-Type': 'application/json'
      }
    }
  );
}

Setting Up Round-Robin Assignment

Distribute new tickets evenly across your team:

// Simple round-robin distributor
let agentIndex = 0;
const agents = [
  { id: 'agent-1', email: 'alice@agency.com' },
  { id: 'agent-2', email: 'bob@agency.com' },
  { id: 'agent-3', email: 'carol@agency.com' }
];

function getNextAgent() {
  const agent = agents[agentIndex];
  agentIndex = (agentIndex + 1) % agents.length;
  return agent;
}

async function processNewTicket(email) {
  const agent = getNextAgent();
  await assignToAgent(email.ticketId, agent.id);
  await sendNotification(agent.email, `New ticket assigned: ${email.subject}`);
}

Automation Patterns That Work

Regardless of which option you choose, several automation patterns improve remote team efficiency:

Auto-Response Templates

Create templates for common scenarios:

Subject: Re: {{ticket.subject}}

Hi {{ticket.client_name}},

Thanks for reaching out. I'm handling your request and will have an update within {{ticket.sla_hours}} hours.

{{#if ticket.needs_escalation}}
I've escalated this to our technical team for deeper investigation.
{{/if}}

Best regards,
{{agent.name}}

SLA Monitoring

Track response times with a simple dashboard:

# SLA tracking script
from datetime import datetime, timedelta

SLA_HOURS = {
    'urgent': 2,
    'high': 4,
    'normal': 24,
    'low': 48
}

def check_sla(ticket):
    priority = ticket.get('priority', 'normal')
    deadline = ticket['created_at'] + timedelta(hours=SLA_HOURS[priority])

    if datetime.now() > deadline:
        return {'status': 'breached', 'remaining': 0}

    remaining = (deadline - datetime.now()).total_seconds() / 3600
    return {'status': 'ok', 'remaining': round(remaining, 1)}

Choosing the Right Setup

Consider these factors when selecting your approach:

Factor Google Groups IMAP + Custom Dedicated Platform
Setup complexity Low High Medium
Cost Included with Workspace Server costs Per-seat subscription
Customization Limited Full control API-dependent
Maintenance Minimal Significant Vendor-managed
Best for Small teams, low volume Technical teams wanting control Scaling agencies

For most remote agencies, starting with Google Groups and upgrading to a dedicated platform as volume grows provides the best balance of simplicity and capability.


Built by theluckystrike — More at zovo.one