Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create email provider adapter layer (for Outlook) #273

Open
6 tasks
elie222 opened this issue Dec 19, 2024 · 0 comments
Open
6 tasks

Create email provider adapter layer (for Outlook) #273

elie222 opened this issue Dec 19, 2024 · 0 comments
Labels
outlook Microsoft Outlook support

Comments

@elie222
Copy link
Owner

elie222 commented Dec 19, 2024

This should only be done after #271 and #272 are completed.

Create a common interface for email operations that works with both Gmail and Outlook.

Example Implementation

This was written by an LLM to give you an idea of how this could be approached:

// types.ts
interface EmailMessage {
  id: string;
  threadId: string; // Gmail threadId or Outlook conversationId
  subject: string;
  snippet: string;
  date: Date;
}

interface EmailProvider {
  // Core methods we need for MVP
  getMessage(messageId: string): Promise<EmailMessage>;
  listMessages(options: {
    folderId?: string, // Label in Gmail, Folder in Outlook
    pageToken?: string,
    maxResults?: number
  }): Promise<{
    messages: EmailMessage[],
    nextPageToken?: string
  }>;
  // Add more as needed
}

// gmail-provider.ts
class GmailProvider implements EmailProvider {
  constructor(private gmail: gmail_v1.Gmail) {}

  async getMessage(messageId: string): Promise<EmailMessage> {
    const msg = await this.gmail.users.messages.get({
      userId: 'me',
      id: messageId
    });
    
    return {
      id: msg.data.id!,
      threadId: msg.data.threadId!,
      subject: getSubject(msg.data), // Helper to parse Gmail headers
      snippet: msg.data.snippet!,
      date: new Date(getDate(msg.data)) // Helper to parse Gmail headers
    };
  }

  async listMessages(options: {
    folderId?: string,
    pageToken?: string,
    maxResults?: number
  }) {
    const response = await this.gmail.users.messages.list({
      userId: 'me',
      labelIds: options.folderId ? [options.folderId] : undefined,
      maxResults: options.maxResults,
      pageToken: options.pageToken
    });

    const messages = await Promise.all(
      response.data.messages!.map(m => this.getMessage(m.id!))
    );

    return {
      messages,
      nextPageToken: response.data.nextPageToken
    };
  }
}

// outlook-provider.ts
class OutlookProvider implements EmailProvider {
  constructor(private graph: Client) {}

  async getMessage(messageId: string): Promise<EmailMessage> {
    const msg = await this.graph.api(`/me/messages/${messageId}`)
      .select('id,conversationId,subject,bodyPreview,receivedDateTime')
      .get();
    
    return {
      id: msg.id,
      threadId: msg.conversationId, // Using conversationId as threadId
      subject: msg.subject,
      snippet: msg.bodyPreview,
      date: new Date(msg.receivedDateTime)
    };
  }

  async listMessages(options: {
    folderId?: string,
    pageToken?: string,
    maxResults?: number
  }) {
    let request = this.graph.api('/me/messages');
    
    if (options.folderId) {
      request = this.graph.api(`/me/mailFolders/${options.folderId}/messages`);
    }

    const response = await request
      .select('id,conversationId,subject,bodyPreview,receivedDateTime')
      .top(options.maxResults || 50)
      .skipToken(options.pageToken)
      .get();

    return {
      messages: response.value.map(msg => ({
        id: msg.id,
        threadId: msg.conversationId,
        subject: msg.subject,
        snippet: msg.bodyPreview,
        date: new Date(msg.receivedDateTime)
      })),
      nextPageToken: response['@odata.nextLink']
    };
  }
}

// factory.ts
function createEmailProvider(type: 'gmail' | 'outlook', client: any): EmailProvider {
  if (type === 'gmail') {
    return new GmailProvider(client);
  }
  return new OutlookProvider(client);
}

// Usage example
const provider = createEmailProvider(session.provider as 'gmail' | 'outlook', client);
const messages = await provider.listMessages({ maxResults: 10 });

Tasks

  1. Create EmailMessage and EmailProvider interfaces
  2. Implement GmailProvider
  3. Implement OutlookProvider
  4. Add factory function
  5. Test basic operations (get/list messages)
  6. Add webhook handling

Done when

  • Can switch between Gmail/Outlook without changing app code
  • Core email operations working with both providers
  • Webhook endpoints handling both providers
@elie222 elie222 added the outlook Microsoft Outlook support label Dec 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
outlook Microsoft Outlook support
Projects
None yet
Development

No branches or pull requests

1 participant