Email Integration LPO Reader
Comprehensive guide to the Email Integration LPO Reader system for automated email processing and client synchronization
Email Integration LPO Reader
The Email Integration LPO (Local Purchase Order) Reader system is a comprehensive solution that enables automatic processing and synchronization of email-based Local Purchase Orders between the Solutech Admin system and client applications. The system integrates with Microsoft Outlook/Azure Email services to read emails with LPO attachments and forwards them to the appropriate client systems.
Key Features
- Automated Email Processing: Reads emails from configured mailboxes with LPO attachments
- Client-Based Routing: Routes emails to appropriate clients based on sender/recipient configuration
- Bulk Synchronization: Supports batch processing of email logs for efficient client synchronization
- Error Handling: Comprehensive error tracking and retry mechanisms
- Audit Trail: Complete logging of all email processing activities
- Real-time Monitoring: API endpoints for monitoring email processing status
- Flexible Configuration: Support for multiple email integration types and client configurations
System Architecture
The Email Integration LPO Reader system consists of several interconnected components:
graph TD
A[Microsoft Outlook/Azure] --> B[MsOutlookController]
B --> C[Email Processing Engine]
C --> D[EmailIntegrationClientDetail]
C --> E[LogEmailIntegrationClientSync]
E --> F[SyncEmailLogsCommand]
F --> G[Client Systems via SAT]
H[Admin Dashboard] --> I[EmailIntegrationClientDetailsController]
I --> D
H --> J[LogEmailIntegrationClientSyncController]
J --> EComponents Overview
- Email Reader: Connects to Microsoft Outlook/Azure to fetch emails
- Processing Engine: Processes emails, extracts attachments, and creates log entries
- Client Management: Manages client configurations for email routing
- Synchronization System: Handles bulk synchronization of processed emails to client systems
- Monitoring Dashboard: Provides real-time monitoring and management capabilities
Core Components
1. MsOutlookController
File: app/Http/Controllers/API/Internal/Integration/EmailIntegration/MsOutlookController.php
The main controller responsible for Microsoft Outlook/Azure email integration.
Key Methods
authenticate(Request $request): Handles OAuth authentication with Microsoft AzurereadLpoEmails(Request $request): Reads and processes LPO emails from the configured mailboxviewLpoEmails(Request $request): Retrieves emails for viewing without processingprocessLpoFromEmail(array $inbox): Core email processing logicgetUserMessages($client, $access_token, $today): Fetches messages from Microsoft Graph API
Authentication Flow
// OAuth authentication with Azure
$response = $client->post("https://login.microsoftonline.com/$tenant_id/oauth2/v2.0/token", [
'form_params' => [
'grant_type' => 'authorization_code',
'client_id' => $this->lpo_details['client_id'],
'client_secret' => $this->lpo_details['client_secret'],
'scope' => $this->lpo_details['scope'],
'code' => $request->code,
'response_mode' => 'query',
'response_type' => 'code',
]
]);2. EmailIntegrationClientDetailsController
File: app/Http/Controllers/API/Internal/Integration/EmailIntegration/EmailIntegrationClientDetailsController.php
Manages client configurations for email integration.
Key Methods
store(StoreRequest $request): Creates new email integration client configurationsindex(Request $request): Lists all client configurations with filteringupdate(UpdateRequest $request, int $id): Updates existing configurationssync(Request $request): Synchronizes configurations to client systemssyncFromSat(Request $request): Handles synchronization requests from client systemsdeleteFromSat(Request $request): Handles deletion requests from client systems
Client Configuration Structure
[
'email' => 'client@example.com',
'email_integration_type' => 'lpo_reader',
'client_sub_accounts_id' => 123,
'status' => 'active',
'sync_status' => 'pending',
'synced_at' => null
]3. LogEmailIntegrationClientSyncController
File: app/Http/Controllers/API/Internal/Integration/EmailIntegration/LogEmailIntegrationClientSyncController.php
Manages email processing logs and provides monitoring capabilities.
Key Methods
index(Request $request): Retrieves email processing logs with filtering and paginationgetClients(): Returns list of available clientstriggerSync(Request $request): Manually triggers email log synchronization
4. SyncEmailLogsCommand
File: app/Console/Commands/Integration/EmailIntegration/SyncEmailLogsCommand.php
Artisan command for synchronizing processed email logs to client systems.
Command Signature
php artisan email-integration:sync-email-logs
{--client-code= : Sync logs for a specific client code only}
{--bulk-size=15 : Number of logs to send in each bulk API request}
{--date= : Date range to sync (e.g., 2024-01-01 or 2024-01-01,2024-01-31). Default is today}Key Features
- Batch Processing: Processes logs in configurable batch sizes
- Bulk Synchronization: Sends multiple logs in single API requests
- Error Recovery: Fallback to individual sync on bulk failures
- Progress Tracking: Real-time progress reporting
- Date Range Support: Flexible date-based filtering
Usage Examples
# Sync today's records for all clients
php artisan email-integration:sync-email-logs
# Sync for specific client
php artisan email-integration:sync-email-logs --client-code=ABC123
# Sync specific date
php artisan email-integration:sync-email-logs --date=2024-01-15
# Sync date range
php artisan email-integration:sync-email-logs --date=2024-01-01,2024-01-31
# Custom bulk size
php artisan email-integration:sync-email-logs --bulk-size=25
# Combined options
php artisan email-integration:sync-email-logs --client-code=ABC123 --date=2024-01-15 --bulk-size=10Email Processing Workflow
Complete Process Flow
sequenceDiagram
participant Admin as Admin System
participant Azure as Microsoft Azure
participant Controller as MsOutlookController
participant DB as Database
participant Client as Client System
Admin->>Controller: Trigger readLpoEmails
Controller->>Azure: Authenticate & Get Access Token
Azure-->>Controller: Access Token
Controller->>Azure: Fetch Emails with Attachments
Azure-->>Controller: Email Data
Controller->>Controller: processLpoFromEmail
Controller->>DB: Store LogEmailIntegrationClientSync
Controller->>Client: Send LPO Data via SAT
Client-->>Controller: Response
Controller->>DB: Update Log StatusEmail Processing Logic
- Authentication: Refresh OAuth token with Microsoft Azure
- Email Retrieval: Fetch emails from configured mailbox using Microsoft Graph API
- Filtering: Process only emails with allowed attachment types (PDF, octet-stream)
- Client Mapping: Match sender/recipient emails to configured clients
- Deduplication: Check for already processed messages
- Data Extraction: Extract email metadata and attachment information
- Storage: Store processing log in
log_email_integration_client_syncs - Client Notification: Send LPO data to client system via SAT transport
- Status Update: Update log with sync status and response
Supported Attachment Types
application/pdfapplication/octet-stream(for specific configured emails)
Email Routing Logic
The system determines the target client using the following priority:
- Sender Email Match: Check if sender email is configured for any client
- Recipient Email Match: If sender not found, check recipient emails
- Fallback: Skip email if no matching client configuration found
Configuration
Azure/Outlook Configuration
Set the following environment variables in your .env file:
# Azure Configuration
AZURE_TENANT_ID=your-tenant-id
AZURE_MAIL_CLIENT_ID=your-client-id
AZURE_MAIL_CLIENT_SECRET=your-client-secret
AZURE_MAIL_REDIRECT_URI=your-redirect-uri
AZURE_MAIL_SCOPE=https://graph.microsoft.com/.default
AZURE_LPO_READER_EMAIL=lpo-reader@yourdomain.comApplication Configuration
Configure in config/azure.php:
return [
'tenant_id' => env('AZURE_TENANT_ID'),
'lpo_reader_email' => env('AZURE_LPO_READER_EMAIL'),
'mail' => [
'client_id' => env('AZURE_MAIL_CLIENT_ID'),
'client_secret' => env('AZURE_MAIL_CLIENT_SECRET'),
'redirect_uri' => env('AZURE_MAIL_REDIRECT_URI'),
'scope' => env('AZURE_MAIL_SCOPE'),
],
];Email Integration Types
Configure allowed email integration types:
const EMAIL_INTEGRATION_TYPE = [
'LPO READER' => 'lpo_reader'
];API Endpoints
Authentication Required Endpoints
All endpoints require auth:api middleware unless specified otherwise.
Client Configuration Management
GET /api/email-integration/index
POST /api/email-integration/store
PUT /api/email-integration/update/{id}
DELETE /api/email-integration/delete/{id}
GET /api/email-integration/clientsSynchronization
POST /api/email-integration/sync-to-satLog Management
GET /api/email-integration/logs
POST /api/email-integration/sync-logsClient Middleware Endpoints
These endpoints use client middleware for external client access:
POST /api/email-integration/logs
POST /api/email-integration/sync-new-email-integration
POST /api/email-integration/sync-delete-email-integrationAzure Email Integration Endpoints
GET /api/v1/azure-email-integration/view-lpo-emails
GET /api/v1/azure-email-integration/message-logs
GET /api/v1/azure-email-integration/access-token
GET /api/v1/azure-email-integration/generate-auth-url
GET /api/v1/azure-email-integration/read-lpo-emailsAPI Examples
Create Email Integration Configuration
POST /api/email-integration/store
Content-Type: application/json
Authorization: Bearer {token}
{
"email": "client@example.com",
"email_integration_type": "lpo_reader",
"client_sub_accounts_id": 123
}Retrieve Email Logs
GET /api/email-integration/logs?page=1&per_page=10&search=subject&start_date=2024-01-01&end_date=2024-01-31
Authorization: Bearer {token}Trigger Manual Sync
POST /api/email-integration/sync-logs
Content-Type: application/json
Authorization: Bearer {token}
{
"client_code": "ABC123"
}Database Schema
email_integration_client_details
Stores client configuration for email integration.
| Column | Type | Description |
|---|---|---|
| id | bigint | Primary key |
| client_sub_accounts_id | bigint | Foreign key to client_sub_accounts |
| email_integration_type | varchar | Type of integration (e.g., 'lpo_reader') |
| varchar | Email address for integration | |
| added_by | bigint | Foreign key to solutes (user who added) |
| status | enum | Active/Inactive status |
| synced_at | timestamp | Last sync timestamp |
| sync_status | varchar | Sync status (pending/success/failed) |
| sync_error_message | text | Error message if sync failed |
| request_json | json | Request payload for sync |
| response_json | json | Response from client system |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Record update time |
log_email_integration_client_syncs
Stores processed email logs for client synchronization.
| Column | Type | Description |
|---|---|---|
| id | bigint | Primary key |
| status | varchar | Processing status (pending/sent/failed) |
| message_id | varchar | Unique email message ID |
| attachment_id | bigint | Email attachment ID |
| client_sub_accounts_id | bigint | Target client sub account |
| from | varchar | Sender email address |
| to | text | Recipient email addresses |
| subject | varchar | Email subject |
| body | text | Email body content |
| sent_at | timestamp | Email sent timestamp |
| received_at | timestamp | Email received timestamp |
| type | varchar | Email type (inbox/sent) |
| error_message | text | Error message if processing failed |
| request_payload | text | Request sent to client |
| file_type | text | Attachment content type |
| attachment_link | text | Attachment content/link |
| synced_to_client_at | timestamp | Client sync timestamp |
| client_sync_response | text | Response from client system |
| created_at | timestamp | Record creation time |
| updated_at | timestamp | Record update time |
| deleted_at | timestamp | Soft delete timestamp |
Data Models
EmailIntegrationClientDetail
File: app/Models/Internal/Integration/EmailIntegration/EmailIntegrationClientDetail.php
Stores client configuration for email integration.
protected $fillable = [
'client_sub_accounts_id',
'email_integration_type',
'email',
'added_by',
'status',
'synced_at',
'request_json',
'response_json',
'sync_status',
'sync_error_message'
];LogEmailIntegrationClientSync
File: app/Models/Internal/Integration/EmailIntegration/LogEmailIntegrationClientSync.php
Stores processed email logs for synchronization to client systems.
protected $fillable = [
'status',
'message_id',
'attachment_id',
'client_sub_accounts_id',
'from',
'to',
'subject',
'body',
'sent_at',
'received_at',
'type',
'error_message',
'request_payload',
'file_type',
'attachment_link',
'synced_to_client_at',
'client_sync_response'
];Error Handling
Error Types and Solutions
1. Authentication Errors
Symptoms: Failed OAuth token refresh, 401 responses from Microsoft Graph API
Handling:
- Automatic token refresh using refresh token
- Logging of authentication failures
- Graceful degradation to prevent service disruption
public function authenticateUsingRefreshToken()
{
try {
$response = $client->post("https://login.microsoftonline.com/$this->tenant_id/oauth2/v2.0/token", [
'form_params' => [
'grant_type' => 'refresh_token',
'refresh_token' => $IntegrationCredentials->refresh_token,
// ... other parameters
]
]);
if ($response->getStatusCode() == 200 || $response->getStatusCode() == 201) {
// Update stored credentials
$IntegrationCredentials->update($responseData);
return $responseData['access_token'];
}
} catch (\Exception $e) {
Log::error('Token refresh failed', ['error' => $e->getMessage()]);
return false;
}
}2. Email Processing Errors
Symptoms: Failed email fetching, malformed email data, attachment processing errors
Handling:
- Skip problematic emails and continue processing
- Log detailed error information
- Update email log status to 'failed'
try {
$this->processLpoFromEmail($inbox);
} catch (\Throwable $th) {
Log::channel('email-integration')->error('Email processing failed', [
'error' => $th->getMessage(),
'trace' => $th->getTraceAsString()
]);
}Monitoring and Logging
Real-time Monitoring
Dashboard Endpoints
-
Email Logs Overview:
/api/email-integration/logs- Paginated list of all email processing logs
- Filtering by date, client, status, and account
- Search functionality across multiple fields
- Supports date range filtering with
start_dateandend_date
-
Manual Sync Trigger:
/api/email-integration/sync-logs- Trigger synchronization for specific clients or all clients
- Returns command output and execution status
Log Status Constants
The system uses predefined status constants for tracking email processing:
const STATUS = [
'SUCCESS' => 'sent', // Email successfully processed and ready for sync
'PENDING' => 'pending', // Email processing in progress
'FAILED' => 'failed' // Email processing failed
];
const TYPE = [
'INBOX' => 'inbox', // Incoming emails
'SENT' => 'sent' // Outgoing emails
];Key Monitoring Fields
The LogEmailIntegrationClientSync model tracks comprehensive data for monitoring:
- Processing Status:
status(pending/sent/failed) - Sync Status:
synced_to_client_at(NULL if not synced) - Error Tracking:
error_messagefor failed operations - Client Response:
client_sync_response(JSON) for sync results - Email Metadata: subject, from, to, body, attachments
- Timing Data: sent_at, received_at, created_at, synced_to_client_at
Search and Filtering
The model includes a comprehensive search scope that searches across:
public function scopeSearch(Builder $query, string $search): Builder
{
return $query->where(function($query) use($search) {
$query->where('log_email_integration_client_syncs.from', 'like', "%$search%")
->orWhere('log_email_integration_client_syncs.to', 'like', "%$search%")
->orWhere('log_email_integration_client_syncs.subject', 'like', "%$search%")
->orWhere('log_email_integration_client_syncs.error_message', 'like', "%$search%")
->orWhere('client_accounts.name', 'like', "%$search%");
});
}Synchronization Command Monitoring
Command Execution Tracking
The SyncEmailLogsCommand provides detailed real-time monitoring during execution:
Starting email logs sync for client code: ABC123...
Using bulk size: 15 logs per API request
Date range: 2024-01-15 00:00:00 to 2024-01-15 23:59:59
Found 3 client(s) with pending email logs.
Processing logs for client: Client A (Code: ABC123)
Batch 1: Processing 100 logs
Bulk chunk 1: Success: 15, Failures: 0
Bulk chunk 2: Success: 15, Failures: 0
Batch 1 completed. Success: 85, Failures: 15
Client Client A completed. Total Success: 85, Total Failures: 15
Overall sync completed in 45 seconds. Total Success: 250, Total Failures: 25Stuck Process Detection
The command includes sophisticated monitoring for stuck processes:
// Track previous batch to detect stuck processing
$previousBatchIds = [];
$consecutiveFailedAttempts = 0;
$maxFailedAttempts = 3; // Maximum number of consecutive failures before skipping
// Check if we're processing the same logs repeatedly (stuck)
$currentBatchIds = $pendingLogs->pluck('id')->toArray();
$isReprocessingSameBatch = !empty($previousBatchIds) &&
count($previousBatchIds) === count($currentBatchIds) &&
count(array_diff($previousBatchIds, $currentBatchIds)) === 0;
if ($isReprocessingSameBatch) {
$consecutiveFailedAttempts++;
if ($consecutiveFailedAttempts >= $maxFailedAttempts) {
// Mark these logs as failed and skip
LogEmailIntegrationClientSync::whereIn('id', $currentBatchIds)->update([
'synced_to_client_at' => now(),
'client_sync_response' => json_encode(['error' => 'Automatic skip after repeated failures'])
]);
}
}Performance Throttling
Built-in delays prevent API overwhelming:
// Small delay between batches to avoid overwhelming the API
if ($pendingLogs->count() === self::BATCH_SIZE) {
usleep(100000); // 100ms delay
}Logging Strategy
Structured Logging Channels
The system uses dedicated logging channels for different aspects:
- email-integration: Primary channel for email processing activities
- General logs: Application-wide tracking in
tbl_logstable
Command-Level Logging
Log::channel('email-integration')->error('Error syncing email logs', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
Log::channel('email-integration')->error('Skipped stuck logs after repeated failures', [
'client_account_id' => $client->client_account_id,
'log_ids' => $currentBatchIds
]);
Log::channel('email-integration')->warning('Email log sync failed', [
'log_id' => $log->id,
'client_account_id' => $clientAccount->id,
'client_name' => $clientAccount->name,
'error' => $errorMessage,
'response' => $response
]);Database Activity Logging
All sync activities are logged to the tbl_logs table:
// Successful bulk sync
DB::table('tbl_logs')->insert([
'log_content' => "Bulk email logs (" . count($logIds) . " logs) synced successfully to client {$clientAccount->name}. Log IDs: " . implode(',', $logIds) . ". Response: " . json_encode($response)
]);
// Individual sync success
DB::table('tbl_logs')->insert([
'log_content' => "Email log {$log->id} synced successfully to client {$clientAccount->name}. Response: " . json_encode($response)
]);
// Sync failure
DB::table('tbl_logs')->insert([
'log_content' => "Email log {$log->id} sync failed for client {$clientAccount->name}. Error: {$errorMessage}. Response: " . json_encode($response)
]);