diff --git a/packages/api/src/routers/svc/emails.ts b/packages/api/src/routers/svc/emails.ts index 0c166cdf6..e81c118ca 100644 --- a/packages/api/src/routers/svc/emails.ts +++ b/packages/api/src/routers/svc/emails.ts @@ -13,6 +13,7 @@ import { getTitleFromEmailSubject, isProbablyArticle, isProbablyNewsletter, + parseEmailAddress, } from '../../utils/parser' import { saveNewsletterEmail } from '../../services/save_newsletter_email' import { saveEmail } from '../../services/save_email' @@ -75,6 +76,7 @@ export function emailsServiceRouter() { } const user = newsletterEmail.user const ctx = { pubsub: createPubSubClient(), uid: user.id } + const parsedFrom = parseEmailAddress(data.from) if (await isProbablyNewsletter(data.html)) { logger.info('handling as newsletter', data) @@ -83,7 +85,7 @@ export function emailsServiceRouter() { email: data.to, title: data.subject, content: data.html, - author: data.from, + author: parsedFrom.name, url: (await findNewsletterUrl(data.html)) || generateUniqueUrl(), unsubMailTo: data.unsubMailTo, unsubHttpUrl: data.unsubHttpUrl, @@ -95,11 +97,11 @@ export function emailsServiceRouter() { return } - if (await isProbablyArticle(data.from, data.subject)) { + if (await isProbablyArticle(parsedFrom.address, data.subject)) { logger.info('handling as article', data) await saveEmail(ctx, { title: getTitleFromEmailSubject(data.subject), - author: data.from, + author: parsedFrom.name, url: generateUniqueUrl(), originalContent: data.html, }) diff --git a/packages/api/src/utils/parser.ts b/packages/api/src/utils/parser.ts index 89fe4b018..abe134b9b 100644 --- a/packages/api/src/utils/parser.ts +++ b/packages/api/src/utils/parser.ts @@ -19,6 +19,7 @@ import { getRepository } from '../entity/utils' import { User } from '../entity/user' import { ILike } from 'typeorm' import { v4 as uuid } from 'uuid' +import addressparser from 'addressparser' const logger = buildLogger('utils.parse') @@ -567,3 +568,14 @@ export const getTitleFromEmailSubject = (subject: string) => { const title = subject.replace(ARTICLE_PREFIX, '') return title.trim() } + +export const parseEmailAddress = (from: string): addressparser.EmailAddress => { + // get author name from email + // e.g. 'Jackson Harper from Omnivore App ' + // or 'Mike Allen ' + const parsed = addressparser(from) + if (parsed.length > 0) { + return parsed[0] + } + return { name: from, address: from } +} diff --git a/packages/api/test/db.ts b/packages/api/test/db.ts index 4af92259b..d1e752c17 100644 --- a/packages/api/test/db.ts +++ b/packages/api/test/db.ts @@ -64,7 +64,7 @@ export const deleteTestUser = async (name: string) => { await AppDataSource.createQueryBuilder() .delete() .from(User) - .where({ email: `${name}@fake.com` }) + .where({ email: `${name}@omnivore.app` }) .execute() } @@ -77,7 +77,7 @@ export const createTestUser = async ( const [newUser] = await createUser({ provider: 'GOOGLE', sourceUserId: 'fake-user-id-' + name, - email: `${name}@fake.com`, + email: `${name}@omnivore.app`, username: name, bio: `i am ${name}`, name: name, @@ -93,7 +93,7 @@ export const createUserWithoutProfile = async (name: string): Promise => { return getRepository(User).save({ source: 'GOOGLE', sourceUserId: 'fake-user-id-' + name, - email: `${name}@fake.com`, + email: `${name}@omnivore.app`, name: name, }) } diff --git a/packages/api/test/resolvers/newsletters.test.ts b/packages/api/test/resolvers/newsletters.test.ts index e82bc003e..465fcc9aa 100644 --- a/packages/api/test/resolvers/newsletters.test.ts +++ b/packages/api/test/resolvers/newsletters.test.ts @@ -28,11 +28,11 @@ describe('Newsletters API', () => { // create test newsletter emails const newsletterEmail1 = await createTestNewsletterEmail( user, - 'Test_email_address_1@fake-email.com' + 'Test_email_address_1@omnivore.app' ) const newsletterEmail2 = await createTestNewsletterEmail( user, - 'Test_email_address_2@fake-email.com' + 'Test_email_address_2@omnivore.app' ) newsletterEmails = [newsletterEmail1, newsletterEmail2] }) diff --git a/packages/api/test/routers/auth.test.ts b/packages/api/test/routers/auth.test.ts index b45fe926c..9dfb301ee 100644 --- a/packages/api/test/routers/auth.test.ts +++ b/packages/api/test/routers/auth.test.ts @@ -47,7 +47,7 @@ describe('auth router', () => { before(() => { password = validPassword username = 'Some_username' - email = `${username}@fake.com` + email = `${username}@omnivore.app` name = 'Some name' }) @@ -397,9 +397,7 @@ describe('auth router', () => { it('redirects to forgot-password page with success message', async () => { const res = await emailResetPasswordReq(email).expect(302) - expect(res.header.location).to.endWith( - '/auth/reset-sent' - ) + expect(res.header.location).to.endWith('/auth/reset-sent') }) }) @@ -434,9 +432,7 @@ describe('auth router', () => { it('redirects to email-login page with error code PENDING_VERIFICATION', async () => { const res = await emailResetPasswordReq(email).expect(302) - expect(res.header.location).to.endWith( - '/auth/reset-sent' - ) + expect(res.header.location).to.endWith('/auth/reset-sent') }) }) }) @@ -448,9 +444,7 @@ describe('auth router', () => { it('redirects to forgot-password page with error code USER_NOT_FOUND', async () => { const res = await emailResetPasswordReq(email).expect(302) - expect(res.header.location).to.endWith( - '/auth/reset-sent' - ) + expect(res.header.location).to.endWith('/auth/reset-sent') }) }) }) @@ -501,9 +495,7 @@ describe('auth router', () => { const res = await resetPasswordRequest(token, 'new_password').expect( 302 ) - expect(res.header.location).to.contain( - '/api/client/auth?tok' - ) + expect(res.header.location).to.contain('/api/client/auth?tok') }) it('resets password', async () => { diff --git a/packages/api/test/routers/pdf_attachments.test.ts b/packages/api/test/routers/pdf_attachments.test.ts index 06053be4a..6110ef4e3 100644 --- a/packages/api/test/routers/pdf_attachments.test.ts +++ b/packages/api/test/routers/pdf_attachments.test.ts @@ -12,7 +12,7 @@ import { getPageById } from '../../src/elastic/pages' describe('PDF attachments Router', () => { const username = 'fakeUser' - const newsletterEmail = 'fakeEmail@fake-email.com' + const newsletterEmail = 'fakeEmail@omnivore.app' let user: User let authToken: string diff --git a/packages/api/test/utils/parser.test.ts b/packages/api/test/utils/parser.test.ts index 5c79e8619..9b78d77b4 100644 --- a/packages/api/test/utils/parser.test.ts +++ b/packages/api/test/utils/parser.test.ts @@ -9,6 +9,7 @@ import { getTitleFromEmailSubject, isProbablyArticle, isProbablyNewsletter, + parseEmailAddress, parsePageMetadata, parsePreparedContent, } from '../../src/utils/parser' @@ -179,3 +180,13 @@ describe('getTitleFromEmailSubject', () => { expect(getTitleFromEmailSubject(subject)).to.eql(title) }) }) + +describe('parseEmailAddress', () => { + const email = 'Tester ' + + it('returns the name and address', () => { + const { name, address } = parseEmailAddress(email) + expect(name).to.eql('Tester') + expect(address).to.eql('tester@omnivore.app') + }) +})