email_helper.rb 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class EmailHelper
  3. =begin
  4. get available driver
  5. result = EmailHelper.available_driver
  6. returns
  7. {
  8. inbound: {
  9. imap: 'IMAP',
  10. pop3: 'POP3',
  11. },
  12. outbound: {
  13. smtp: 'SMTP - configure your own outgoing SMTP settings',
  14. sendmail: 'Local MTA (Sendmail/Postfix/Exim/...) - use server setup',
  15. },
  16. }
  17. =end
  18. def self.available_driver
  19. if Setting.get('system_online_service')
  20. return {
  21. inbound: {
  22. imap: __('IMAP'),
  23. pop3: __('POP3'),
  24. },
  25. outbound: {
  26. smtp: __('SMTP - configure your own outgoing SMTP settings'),
  27. },
  28. }
  29. end
  30. {
  31. inbound: {
  32. imap: __('IMAP'),
  33. pop3: __('POP3'),
  34. },
  35. outbound: {
  36. smtp: __('SMTP - configure your own outgoing SMTP settings'),
  37. sendmail: __('Local MTA (Sendmail/Postfix/Exim/…) - use server setup'),
  38. },
  39. }
  40. end
  41. =begin
  42. get mail parts
  43. user, domain = EmailHelper.parse_email('somebody@example.com')
  44. returns
  45. [user, domain]
  46. =end
  47. def self.parse_email(email)
  48. user = nil
  49. domain = nil
  50. if email =~ %r{^(.+?)@(.+?)$}
  51. user = $1
  52. domain = $2
  53. end
  54. [user, domain]
  55. end
  56. =begin
  57. get list of providers with inbound and outbound settings
  58. map = EmailHelper.provider(email, password)
  59. returns
  60. {
  61. google: {
  62. domain: 'gmail.com|googlemail.com|gmail.de',
  63. inbound: {
  64. adapter: 'imap',
  65. options: {
  66. host: 'imap.gmail.com',
  67. port: 993,
  68. ssl: true,
  69. user: email,
  70. password: password,
  71. },
  72. },
  73. outbound: {
  74. adapter: 'smtp',
  75. options: {
  76. host: 'smtp.gmail.com',
  77. port: 25,
  78. start_tls: true,
  79. user: email,
  80. password: password,
  81. }
  82. },
  83. },
  84. ...
  85. }
  86. =end
  87. def self.provider(email, password)
  88. # check domain based attributes
  89. {
  90. google_imap: {
  91. domain: 'gmail|googlemail|google',
  92. inbound: {
  93. adapter: 'imap',
  94. options: {
  95. host: 'imap.gmail.com',
  96. port: 993,
  97. ssl: true,
  98. user: email,
  99. password: password,
  100. },
  101. },
  102. outbound: {
  103. adapter: 'smtp',
  104. options: {
  105. host: 'smtp.gmail.com',
  106. port: 587,
  107. start_tls: true,
  108. user: email,
  109. password: password,
  110. }
  111. },
  112. },
  113. microsoft: {
  114. domain: 'outlook.com|hotmail.com',
  115. inbound: {
  116. adapter: 'imap',
  117. options: {
  118. host: 'imap-mail.outlook.com',
  119. port: 993,
  120. ssl: true,
  121. user: email,
  122. password: password,
  123. },
  124. },
  125. outbound: {
  126. adapter: 'smtp',
  127. options: {
  128. host: 'smtp-mail.outlook.com',
  129. port: 587,
  130. start_tls: true,
  131. user: email,
  132. password: password,
  133. }
  134. },
  135. },
  136. google_pop3: {
  137. domain: 'gmail|googlemail|google',
  138. inbound: {
  139. adapter: 'pop3',
  140. options: {
  141. host: 'pop.gmail.com',
  142. port: 995,
  143. ssl: true,
  144. user: email,
  145. password: password,
  146. },
  147. },
  148. outbound: {
  149. adapter: 'smtp',
  150. options: {
  151. host: 'smtp.gmail.com',
  152. port: 587,
  153. start_tls: true,
  154. user: email,
  155. password: password,
  156. }
  157. },
  158. },
  159. }
  160. end
  161. =begin
  162. get possible inbound settings based on mx
  163. map = EmailHelper.provider_inbound_mx(user, email, password, mx_domains)
  164. returns
  165. {
  166. adapter: 'imap',
  167. options: {
  168. host: mx_domains[0],
  169. port: 993,
  170. ssl: true,
  171. user: user,
  172. password: password,
  173. },
  174. },
  175. {
  176. adapter: 'imap',
  177. options: {
  178. host: mx_domains[0],
  179. port: 993,
  180. ssl: true,
  181. user: email,
  182. password: password,
  183. },
  184. },
  185. =end
  186. def self.provider_inbound_mx(user, email, password, mx_domains)
  187. inbounds = []
  188. mx_domains.each do |domain|
  189. inbound = [
  190. {
  191. adapter: 'imap',
  192. options: {
  193. host: domain,
  194. port: 993,
  195. ssl: true,
  196. user: user,
  197. password: password,
  198. },
  199. },
  200. {
  201. adapter: 'imap',
  202. options: {
  203. host: domain,
  204. port: 993,
  205. ssl: true,
  206. user: email,
  207. password: password,
  208. },
  209. },
  210. ]
  211. inbounds.concat(inbound)
  212. end
  213. inbounds
  214. end
  215. =begin
  216. get possible inbound settings based on guess
  217. map = EmailHelper.provider_inbound_guess(user, email, password, domain)
  218. returns
  219. {
  220. adapter: 'imap',
  221. options: {
  222. host: "mail.#{domain}",
  223. port: 993,
  224. ssl: true,
  225. user: user,
  226. password: password,
  227. },
  228. },
  229. {
  230. adapter: 'imap',
  231. options: {
  232. host: "mail.#{domain}",
  233. port: 993,
  234. ssl: true,
  235. user: email,
  236. password: password,
  237. },
  238. },
  239. ...
  240. =end
  241. def self.provider_inbound_guess(user, email, password, domain)
  242. [
  243. {
  244. adapter: 'imap',
  245. options: {
  246. host: "mail.#{domain}",
  247. port: 993,
  248. ssl: true,
  249. user: user,
  250. password: password,
  251. },
  252. },
  253. {
  254. adapter: 'imap',
  255. options: {
  256. host: "mail.#{domain}",
  257. port: 993,
  258. ssl: true,
  259. user: email,
  260. password: password,
  261. },
  262. },
  263. {
  264. adapter: 'imap',
  265. options: {
  266. host: "imap.#{domain}",
  267. port: 993,
  268. ssl: true,
  269. user: user,
  270. password: password,
  271. },
  272. },
  273. {
  274. adapter: 'imap',
  275. options: {
  276. host: "imap.#{domain}",
  277. port: 993,
  278. ssl: true,
  279. user: email,
  280. password: password,
  281. },
  282. },
  283. {
  284. adapter: 'pop3',
  285. options: {
  286. host: "mail.#{domain}",
  287. port: 995,
  288. ssl: true,
  289. user: user,
  290. password: password,
  291. },
  292. },
  293. {
  294. adapter: 'pop3',
  295. options: {
  296. host: "mail.#{domain}",
  297. port: 995,
  298. ssl: true,
  299. user: email,
  300. password: password,
  301. },
  302. },
  303. {
  304. adapter: 'pop3',
  305. options: {
  306. host: "pop.#{domain}",
  307. port: 995,
  308. ssl: true,
  309. user: user,
  310. password: password,
  311. },
  312. },
  313. {
  314. adapter: 'pop3',
  315. options: {
  316. host: "pop.#{domain}",
  317. port: 995,
  318. ssl: true,
  319. user: email,
  320. password: password,
  321. },
  322. },
  323. {
  324. adapter: 'pop3',
  325. options: {
  326. host: "pop3.#{domain}",
  327. port: 995,
  328. ssl: true,
  329. user: user,
  330. password: password,
  331. },
  332. },
  333. {
  334. adapter: 'pop3',
  335. options: {
  336. host: "pop3.#{domain}",
  337. port: 995,
  338. ssl: true,
  339. user: email,
  340. password: password,
  341. },
  342. },
  343. ]
  344. end
  345. =begin
  346. get possible outbound settings based on mx
  347. map = EmailHelper.provider_outbound_mx(user, email, password, mx_domains)
  348. returns
  349. {
  350. adapter: 'smtp',
  351. options: {
  352. host: domain,
  353. port: 25,
  354. start_tls: true,
  355. user: user,
  356. password: password,
  357. },
  358. },
  359. {
  360. adapter: 'smtp',
  361. options: {
  362. host: domain,
  363. port: 25,
  364. start_tls: true,
  365. user: email,
  366. password: password,
  367. },
  368. },
  369. =end
  370. def self.provider_outbound_mx(user, email, password, mx_domains)
  371. outbounds = []
  372. mx_domains.each do |domain|
  373. outbound = [
  374. {
  375. adapter: 'smtp',
  376. options: {
  377. host: domain,
  378. port: 465,
  379. start_tls: true,
  380. user: user,
  381. password: password,
  382. },
  383. },
  384. {
  385. adapter: 'smtp',
  386. options: {
  387. host: domain,
  388. port: 465,
  389. start_tls: true,
  390. user: email,
  391. password: password,
  392. },
  393. },
  394. {
  395. adapter: 'smtp',
  396. options: {
  397. host: domain,
  398. port: 587,
  399. user: user,
  400. password: password,
  401. },
  402. },
  403. {
  404. adapter: 'smtp',
  405. options: {
  406. host: domain,
  407. port: 587,
  408. user: email,
  409. password: password,
  410. },
  411. },
  412. {
  413. adapter: 'smtp',
  414. options: {
  415. host: domain,
  416. port: 25,
  417. start_tls: true,
  418. user: user,
  419. password: password,
  420. },
  421. },
  422. {
  423. adapter: 'smtp',
  424. options: {
  425. host: domain,
  426. port: 25,
  427. start_tls: true,
  428. user: email,
  429. password: password,
  430. },
  431. },
  432. ]
  433. outbounds.concat(outbound)
  434. end
  435. outbounds
  436. end
  437. =begin
  438. get possible outbound settings based on guess
  439. map = EmailHelper.provider_outbound_guess(user, email, password, domain)
  440. returns
  441. {
  442. adapter: 'imap',
  443. options: {
  444. host: "mail.#{domain}",
  445. port: 993,
  446. ssl: true,
  447. user: user,
  448. password: password,
  449. },
  450. },
  451. {
  452. adapter: 'imap',
  453. options: {
  454. host: "mail.#{domain}",
  455. port: 993,
  456. ssl: true,
  457. user: email,
  458. password: password,
  459. },
  460. },
  461. ...
  462. =end
  463. def self.provider_outbound_guess(user, email, password, domain)
  464. [
  465. {
  466. adapter: 'smtp',
  467. options: {
  468. host: "mail.#{domain}",
  469. port: 465,
  470. start_tls: true,
  471. user: user,
  472. password: password,
  473. },
  474. },
  475. {
  476. adapter: 'smtp',
  477. options: {
  478. host: "mail.#{domain}",
  479. port: 465,
  480. start_tls: true,
  481. user: email,
  482. password: password,
  483. },
  484. },
  485. {
  486. adapter: 'smtp',
  487. options: {
  488. host: "smtp.#{domain}",
  489. port: 465,
  490. start_tls: true,
  491. user: user,
  492. password: password,
  493. },
  494. },
  495. {
  496. adapter: 'smtp',
  497. options: {
  498. host: "smtp.#{domain}",
  499. port: 465,
  500. start_tls: true,
  501. user: email,
  502. password: password,
  503. },
  504. },
  505. {
  506. adapter: 'smtp',
  507. options: {
  508. host: "mail.#{domain}",
  509. port: 587,
  510. start_tls: true,
  511. user: user,
  512. password: password,
  513. },
  514. },
  515. {
  516. adapter: 'smtp',
  517. options: {
  518. host: "mail.#{domain}",
  519. port: 587,
  520. start_tls: true,
  521. user: email,
  522. password: password,
  523. },
  524. },
  525. {
  526. adapter: 'smtp',
  527. options: {
  528. host: "smtp.#{domain}",
  529. port: 587,
  530. start_tls: true,
  531. user: user,
  532. password: password,
  533. },
  534. },
  535. {
  536. adapter: 'smtp',
  537. options: {
  538. host: "smtp.#{domain}",
  539. port: 587,
  540. start_tls: true,
  541. user: email,
  542. password: password,
  543. },
  544. },
  545. {
  546. adapter: 'smtp',
  547. options: {
  548. host: "mail.#{domain}",
  549. port: 25,
  550. start_tls: true,
  551. user: user,
  552. password: password,
  553. },
  554. },
  555. {
  556. adapter: 'smtp',
  557. options: {
  558. host: "mail.#{domain}",
  559. port: 25,
  560. start_tls: true,
  561. user: email,
  562. password: password,
  563. },
  564. },
  565. {
  566. adapter: 'smtp',
  567. options: {
  568. host: "smtp.#{domain}",
  569. port: 25,
  570. start_tls: true,
  571. user: user,
  572. password: password,
  573. },
  574. },
  575. {
  576. adapter: 'smtp',
  577. options: {
  578. host: "smtp.#{domain}",
  579. port: 25,
  580. start_tls: true,
  581. user: email,
  582. password: password,
  583. },
  584. },
  585. ]
  586. end
  587. =begin
  588. get dns mx records of domain
  589. mx_records = EmailHelper.mx_records('example.com')
  590. returns
  591. ['mx1.example.com', 'mx2.example.com']
  592. =end
  593. def self.mx_records(domain)
  594. mail_exchangers = mxers(domain)
  595. if mail_exchangers && mail_exchangers[0]
  596. Rails.logger.info "MX for #{domain}: #{mail_exchangers} - #{mail_exchangers[0][0]}"
  597. end
  598. mx_records = []
  599. if mail_exchangers && mail_exchangers[0] && mail_exchangers[0][0]
  600. mx_records.push mail_exchangers[0][0]
  601. end
  602. mx_records
  603. end
  604. def self.mxers(domain)
  605. begin
  606. mxs = Resolv::DNS.open do |dns|
  607. ress = dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
  608. ress.map do |r|
  609. [r.exchange.to_s, IPSocket.getaddress(r.exchange.to_s), r.preference]
  610. end
  611. end
  612. rescue => e
  613. Rails.logger.error e
  614. end
  615. mxs
  616. end
  617. end