fix: Mimecast correct credentials, x-mc-account header, no-ms date format, accountCode in body

This commit is contained in:
lorentz 2026-03-17 16:38:13 -04:00
parent 25bb70cfa6
commit c1479511bf
3 changed files with 36 additions and 15 deletions

View file

@ -107,6 +107,7 @@ services:
MIMECAST_CLIENT_ID: ${MIMECAST_CLIENT_ID}
MIMECAST_CLIENT_SECRET: ${MIMECAST_CLIENT_SECRET}
MIMECAST_BASE_URL: ${MIMECAST_BASE_URL:-https://api.services.mimecast.com}
MIMECAST_ACCOUNT_CODE: ${MIMECAST_ACCOUNT_CODE}
# IT Glue Configuration
ITGLUE_API_KEY: ${ITGLUE_API_KEY}

View file

@ -15,6 +15,7 @@ export interface MimecastConfig {
clientId: string;
clientSecret: string;
baseUrl?: string;
accountCode?: string;
}
interface TokenResponse {
@ -82,12 +83,24 @@ export class MimecastClient {
private readonly clientId: string;
private readonly clientSecret: string;
private readonly baseUrl: string;
private readonly accountCode: string;
private tokenCache: TokenCache | null = null;
constructor(config: MimecastConfig) {
this.clientId = config.clientId;
this.clientSecret = config.clientSecret;
this.baseUrl = (config.baseUrl ?? 'https://api.services.mimecast.com').replace(/\/$/, '');
this.accountCode = config.accountCode ?? '';
}
/**
* Format a Date to the Mimecast-required format: yyyy-MM-ddTHH:mm:ss+0000
* Note: NO milliseconds the API rejects .SSS variants
*/
static formatDate(d: Date): string {
const pad = (n: number) => String(n).padStart(2, '0');
return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}` +
`T${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())}+0000`;
}
// ── Auth ─────────────────────────────────────────────────────────────────
@ -135,13 +148,18 @@ export class MimecastClient {
url = `${url}?${new URLSearchParams(params).toString()}`;
}
const headers: Record<string, string> = {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
};
if (this.accountCode) {
headers['x-mc-account'] = this.accountCode;
}
const res = await fetch(url, {
method,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
headers,
body: body ? JSON.stringify(body) : undefined,
});
@ -160,15 +178,19 @@ export class MimecastClient {
* Response: { data: [{ trackedEmails: [...], pageToken: string }] }
*/
async getMessageLogs(options: {
from: string; // ISO datetime string
to: string;
from: Date;
to: Date;
cursor?: string;
pageSize?: number;
senderFilter?: string;
}): Promise<PaginatedResult<MimecastMessage>> {
const reqData: Record<string, any> = {
from: options.from,
to: options.to,
pageSize: options.pageSize ?? 500,
accountCode: this.accountCode,
advancedTrackAndTraceOptions: {
from: options.senderFilter ?? '',
},
start: MimecastClient.formatDate(options.from),
end: MimecastClient.formatDate(options.to),
};
if (options.cursor) reqData.pageToken = options.cursor;
@ -380,7 +402,7 @@ export class MimecastClient {
*/
async testConnection(): Promise<{ ok: boolean; accountName?: string; packageName?: string; error?: string }> {
try {
const data = await this.request<any>('POST', '/api/account/get-account', { data: [{}] });
const data = await this.request<any>('POST', '/api/account/get-account', { data: [{ accountCode: this.accountCode }] });
const account = data.data?.[0] ?? {};
return {
ok: true,
@ -406,6 +428,7 @@ export function getMimecastClient(): MimecastClient {
clientId,
clientSecret,
baseUrl: process.env.MIMECAST_BASE_URL ?? 'https://api.services.mimecast.com',
accountCode: process.env.MIMECAST_ACCOUNT_CODE ?? '',
});
}
return _client;

View file

@ -196,12 +196,9 @@ export async function syncMimecastMessages(
let total = 0;
let cursor: string | null = null;
const from = fromDate.toISOString();
const to = toDate.toISOString();
do {
try {
const result = await client.getMessageLogs({ from, to, cursor: cursor ?? undefined, pageSize: 500 });
const result = await client.getMessageLogs({ from: fromDate, to: toDate, cursor: cursor ?? undefined, pageSize: 500 });
if (result.items.length > 0) {
total += await upsertMessages(result.items);
}