10,000 Matching Annotations
  1. Jan 2023
    1. Since Rails creates callbacks for dependent associations, always call before_destroy callbacks that perform validation with prepend: true.
    1. This depends on the ruby code. Some projects will be semi-dormant due to various reasons. That's for us to address as a community. Are we going to let a single decade-old gem prevent us from moving Ruby forward? What's the threshold? There's libraries out there that don't work on Ruby 1.9. We left them behind or replaced them. And are people depending on a gem that's unmaintained really going to be the ones to jump on Ruby 3.0 the day after Christmas 2020? This is also still supposition. Name some gems that are unmaintained and in wide use. We can fix them! We have the technology! In my opinion, if matz's objective is to make the transition to ruby 3.0 simple, then it actually makes a lot of sense to postpone frozen strings by default. Postpone until when? 3.1? So then 3.1 will be the hard break? They've been discussed for what, ten years now? How long is long enough? We've added many ways for people to start transitioning to immutable literal strings, and people are using those mechanisms widely. We've pushed this transition a long time, and we still have another year until 3.0 is out and longer than that until people will need to make a move. What is the threshold for being "ready" to make this change? Unless we're planning to wait until Ruby 4.0 in 2030 to do this, I think we should do it now. I use frozen strings in most of my ruby projects, most of them set to true via the toplevel comment, so either way, it would not affect me. Exactly. Most people already do use frozen string literals. And adding a pragma means we can transition troublesome code to the new way with a single line per affected file. Heck, we can even add --enable:mutable-literal-string for people that are stuck with some of that old unmaintained code, allowing them to have a soft landing.
    2. I guess the interaction between the "false" state and the current runtime default is what has me confused. I see "true" and "false" here more like "on" and "off", and if frozen-string-literal is off, to me that means it does nothing at all and whatever defaults are in place take effect.
    3. I'm still against frozen-string-literal by default. It is arguable if the string creation limits performance so much in real-world programs. We need to first measure how much Ruby can be faster by frozen-string-literal. If it is not significant, Ruby should prefer dynamics and flexibility.
    1. because most languages treat strings as immutable, which helps ensure you don't accidentally modify them and can improve performance. Fewer state changes in a program mean less complexity. It's better to opt-in to mutability after careful consideration rather than making everything mutable by default. What is immutability and why should I worry about it? may help.
    1. Until we release 2.0 you should continue to use 1.6.4, which can be found at bblimke/webmock.

      https://github.com/bblimke/webmock is at 3.18.1 so this repo is apparently abandoned and should be archived

    1. bundle update rails-controller-testing --conservative. The –conservative flag says when updating this gem do no update any of its dependencies. Using the –conservative flag with bundle is really useful for minimizing changesets as well as avoiding upgrading things that you don’t need to upgrade.
    1. Judge Domino is a game in which players judge if toppling a line of dominoes will succeed or fail. Players take turns adding to the line, but to score points, you must make others think that the toppling will fail. Can you baffle other players' judgment?
    1. There's a fundamental error in your question: commits are not diffs; commits are snapshots. This might seem like a distinction without a difference—and for some commits, it is. But for merge commits, it's not.
    2. For ordinary commits, it's trivially obvious what to compare: compare this commit's snapshot to the previous (i.e., parent) commit's snapshot. So that is what git show does (and git log -p too): it runs a git diff from the parent commit, to this commit. Merge commits don't have just one parent commit, though. They have two parents.1 This is what makes them "merge commits" in the first place: the definition of a merge commit is a commit with at least two parents.
  2. datatracker.ietf.org datatracker.ietf.org
    1. If the client knows the access token expired, it skips to step (G); otherwise, it makes another protected resource request.

      It doesn't have to wait until it gets an invalid token error. It can independently be checking the expiration time before making a request, and if it sees that it has expired, don't even bother making the request, just skip directly to using the refresh token.

    2. Figure 2: Refreshing an Expired Access Token
    3. Unlike access tokens, refresh tokens are intended for use only with authorization servers and are never sent to resource servers.

      Interesting observation...

    1. ou play a level of one hole and then move onto the next stage to play another hole.

      onto -> on to

    1. belongs_to does not ensure reference consistency, so depending on the use case, you might also need to add a database-level foreign key constraint on the reference column, like this: create_table :books do |t| t.belongs_to :author, foreign_key: true # ... end
    1. class String alias strip_ws strip def strip chr=nil return self.strip_ws if chr.nil? self.gsub /^[#{Regexp.escape(chr)}]*|[#{Regexp.escape(chr)}]*$/, '' end end
    2. No, in Python "[ [] foo [] boo [][]] ".strip(" []") returns "foo [] boo".

      I would have expected it would remove the string " []", not the occurrences of any of the characters within the string...

    3. There is no such method in ruby, but you can easily define it like: def my_strip(string, chars) chars = Regexp.escape(chars) string.gsub(/\A[#{chars}]+|[#{chars}]+\z/, "") end
    4. wer lesen kann, ist klar im Vorteil
    1. And misunderstandings so easily occur here, when we're talking about encodings, but not those encodings, the other encoding, which is really charset. And it's especially hard because you can't visually tell the difference and in so many cases everything still works even though it is wrong.
    1. Did you see the rest of my post too? If you are reading the replies only in email, don't. Visit the forum and open the thread. Because when we edit a post, you don't receive the modification by email, only the initial post. I added few things to my last one...
    1. Nice try, but it's still full of exceptions. To make the above jingle accurate, it'd need to be something like: I before e, except after c Or when sounded as 'a' as in 'neighbor' and 'weigh' Unless the 'c' is part of a 'sh' sound as in 'glacier' Or it appears in comparatives and superlatives like 'fancier' And also except when the vowels are sounded as 'e' as in 'seize' Or 'i' as in 'height' Or also in '-ing' inflections ending in '-e' as in 'cueing' Or in compound words as in 'albeit' Or occasionally in technical words with strong etymological links to their parent languages as in 'cuneiform' Or in other numerous and random exceptions such as 'science', 'forfeit', and 'weird'.
    1. The Templates API allows you to store, version, duplicate, and delete any templates on your account.

      Duplicate? How do you duplicate? We want this ability,but could not find it.

    1. Because endpoints are URLs, you can – and should – monitor them to ensure they stay online. When talking about online services and websites, you’ll often hear the word “uptime”. This is the percentage of time your application stays up – in other words, the percentage of time your app is accessible and functioning. Outages and performance errors will lower your overall percentage.Monitoring your endpoints also gives you metrics on which endpoints are being accessed and what types of API calls developers are making. This can help you track user behavior, and gain insight into which endpoints are highly trafficked so you can maintain your performance.
    2. As an email service provider (ESP), Mailgun’s API support is all about programmatic solutions to make your email program more efficient and successful at scale. Our email API is a specific type of API that you can use to connect your web app or platform to an ESP to use its features within your own application.
    1. The array subscript numbers are written within square brackets. By default PostgreSQL uses a one-based numbering convention for arrays, that is, an array of n elements starts with array[1] and ends with array[n].
    1. You can use ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags to configure pg_dump. For example, to exclude comments from your structure dump, add this to an initializer: ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = ['--no-comments']
    1. with a low level understanding of computing and tech

      Does "low level" here mean "not much" or a lot (he's familiar with the low level of these technologies)?

    1. I was very surprised to discover that Finder has no native SFTP integration. As an everyday Gnome user, it is unbelievable to me, how this can even be
    1. The best way to learn common table expressions is through practice. I recommend LearnSQL.com's interactive Recursive Queries course. It contains over 100 exercises that teach CTEs starting with the basics and progressing to advanced topics like recursive common table expressions.
    1. It's usually undesirable to add a default scope. It will take more effort to work around and will cause more headaches. If you know you need a default scope, it's easy to add yourself .
    2. dependent: :destroy associations are deleted when performing soft-destroys requiring any dependent records to also be acts_as_paranoid to avoid losing data.
    3. I've worked with and have helped maintain paranoia for a while. I'm convinced it does the wrong thing for most cases. Paranoia and acts_as_paranoid both attempt to emulate deletes by setting a column and adding a default scope on the model. This requires some ActiveRecord hackery, and leads to some surprising and awkward behaviour.
    1. paranoia has some surprising behaviour (like overriding ActiveRecord's delete and destroy) and is not recommended for new projects. See discard's README for more details. Paranoia will continue to accept bug fixes and support new versions of Rails but isn't accepting new features.
    2. paranoia has some surprising behaviour (like overriding ActiveRecord's delete and destroy)
    1. The solution is pretty simple. In the MaterialsController just show all the materials that do not have a :deleted_at column set. In the MaterialsTrashController just show only the Materials with :delete_at controller. I can solve the whole problem with one simple filter that would take me like 1 minute to implement. We don’t need any of the problems above. They simply will not exist.
    2. But it does not work, because the association with authors will return empty authors for the Material as the materials are also soft deleted.
    3. The problem is that Globalize knows nothing about acts_as_paranoid. You can delete a Material, and it should delete the translations, but when you try to recover the Material then there is an error because of how the translations are implemented and the order in which the translations and the Material are recovered. Which record should be recovered first?
    4. Remember that the Material has all of its translations for the title in a table that just got soft deleted. So the correct answer is “nil”. The title of the delete material is nil.
    5. You can workaround this with material.translations.with_deleted.where(locale: I18n.locale).first.title But this is quite ugly.
    1. check the Subject Line Preview tool to preview your email subject line on a variety of clients

      e-mail subject lines

  3. Dec 2022
    1. Breaking other user's YAML overrides is not a big deal as long as this was clearly stated in the docs and the version number is bumped accordingly.
    1. 2. Use a preference center The best way to know what topics your subscribers care about and how frequently they want to hear from your brand is to ask them. Create an email preference center so when an individual goes to subscribe to your email list, they have the power to opt-in and out of specific forms of communication. For example, maybe an individual only wants to know when you’re having sales but doesn’t care to receive your monthly newsletter and weekly marketing emails. The preference center allows them to self-select which of these emails they receive, allowing you to send more targeted emails without pestering your recipients.

      .

    1. I was thinking this morning how House Church is much like a wagon train going across the wilderness. By the time you get to your destination, you know everything about everyone on that train. You help each other and protect each other and become bonded together. The institutional church is like a high-speed bullet train. It's more comfortable, more efficient and takes you the same distance in a shorter amount of time. Also you have barely enough time to get acquainted with 1 or 2 people.
    2. For those who can hear. When you name you divide. There is zero biblical precedent for naming a certain group of believers .... Identify with the body of Christ in your area .... We are exhorted to, "let there be no division among you".The only use of "churches" plural in scripture refers to the church in different locations. There was no such thought of "churches" within one locality. Love you all and pray more will see this so the world may see we are one and know that Jesus was sent by the Father.It's important John 17:20-23
    3. no need any name whatsoever bro It's who we are that's important.
    4. Often it helps to have the location or region in the name, a mountain near you or the name of the valley you are in, or a creek, stream or river. What says 'home' about where you are?
    5. Pleeaasse don't give "it" a name.There is no "it". You believers are part of the church in your location and you meet together.There is zero biblical precedent for a group of believers giving their particular group a name.I understand that nearly all believers do .... That in no way makes it right.Names seperate us from others of the church in our area.
    6. Paul TrosclairHow is it biblical to name a church ?2wBeth BalmesPaul Trosclair geographical. E.g.Church in Corinth. Church in Ephesus.2wJohanna WhittakerBeth Balmes .. Paul's letters were to the CHURCHES (ekklesia) in ...
    7. If you practice the error of "We are of Paul", or "We are of Apollos" , that's rank heresy.
    1. whereas division implies separation (“portion,” “piece,” “unit”) diversity implies variety within a whole (“assortment,” “heterogeneity”)
    2. But, like the British before us, the Russian Czar, or the Weimar Republic, who can define where revolution originates? They all had at least one thing in common: they were all caught by surprise.

      .

    3. I once had a cut on my arm. Someone asked me, is it serious? “It depends,” I replied, “on how much I scratch.”
    1. In essentials, unity; in non-essentials, liberty; in all things, charity (kindness). Now we may not even agree about what the essentials are, but the key, I think, is that last bit – in all things, charity. Hold a generous heart for all, whether they agree with you or disagree with you.
    1. 4NO POSTING OR UPLOADING VIDEOS OF ANY KINDTo protect the quality of our group & prevent members from being solicited products & services - we don't allow any videos because we can't monitor what's being said word for word. Written post only.

      annotation meta: may need new tag: - can't effectively monitor

    2. 3NO SELF PROMOTION, RECRUITING, OR DM SPAMMINGMembers love our group because it's SAFE. We are very strict on banning members who blatantly self promote their product or services in the group OR secretly private message members to recruit them.
    3. 2NO POST FROM FAN PAGES / ARTICLES / VIDEO LINKSOur mission is to cultivate the highest quality content inside the group. If we allowed videos, fan page shares, & outside websites, our group would turn into spam fest. Original written content only
    4. 1NO POSTING LINKS INSIDE OF POST - FOR ANY REASONWe've seen way too many groups become a glorified classified ad & members don't like that. We don't want the quality of our group negatively impacted because of endless links everywhere. NO LINKS
    1. Web and mobile apps, SPAs, and SAAS products with thoughtful UX and robust implementation.
    1. Anyway, through that process, we were able to see just how many competing priorities we had as an organization, and that we needed to stop testing the waters and actually commit to one specific direction.
    1. Since there is no measurable performance advantage for either, any time (however marginal) spent thinking or talking about a choice between the two is wasted. When you prefer single quoted strings, you have to think when you need interpolation. When you use double quoted strings, you never have to think. (I'd also add, anecdotally, that apostrophes are more prevalent in strings than double quotes, which again means less thinking when using double-quoted strings.) Therefore always using double-quoted strings results in the least possible wasted time and effort.
    1. In this case, if the constant Admin::User was already loaded at the time Admin::UserManager.all was called, then it would return Admin::User objects.However, if Admin::User was not yet auto-loaded, but User was, Admin::UserManager.all would instead return User objects!
    1. That may be fine, but if you prefer you can also pass overrides to the inflectors used by the autoloaders: # config/initializers/zeitwerk.rb Rails.autoloaders.main.inflector.inflect("vat" => "VAT") Copy With this option you have more control, because only files called exactly vat.rb or directories exactly called vat will be inflected as VAT. A file called vat_rules.rb is not affected by that and can define VatRules just fine. This may be handy if the project has this kind of naming inconsistencies.
    1. I assume that the goal of synchronizing timestamps is so that the primary record and its Version can be correlated by future reporting queries. I've always thought this is an odd feature, given that said correlation can be more reliably and performantly achieved by use of the foreign key (item_id). So, I'd like to suggest that we add an option to disable this feature. For the new option's name, I'll suggest synchronize_version_creation_timestamp. It would be true by default. has_paper_trail(synchronize_version_creation_timestamp: false) I'm open to disabling this feature by default, in a future major release, after a reasonable deprecation period.
    1. GET if to obtain information. There should not be any "body" data sent with that request. This will not trigger error, but we just simply don't look there in GET request. Only query string parameters ale allowed. This request will never change anything, you can call it as many times as you want. It is called that GET is IDEMPOTENT request. POST is to add new or modify existing information. If request url doesn't contain resource ID then we will treat that as new data that must be inserted. If you want to modify existing data you need to specify an ID in the Rrequest URL (like POST /contacts/hg5fF). POST is NOT IDEMPOTENT, you need to be carefull to not send the same request twice... DELETE is only to remove infomration. As a general rule we do not allow to add any "body" data to that type of request nor we allow any query string. This should be just simply DELETE /contacts/hg5fF.
    1. Our API v3 uses the terminology from the previous version of GetResponse. Campaigns and lists are the same resource under a different name. For now, please refer to lists as campaigns. Our API v4 will use the updated terminology.
    2. You can filter the resource using criteria specified as query[*]. You can provide multiple criteria, to use AND logic. You can sort the resource using parameters specified as sort[*]. You can specify multiple fields to sort by.
    3. Enum:"add" "delete" An additional flag parameter with the value add will add masks provided in the request body to the list. A flag value delete will delete masks from the list. If there's no parameter provided, masks are replaced.
    1. I'm glad this isn't a lego set because it would cost you an arm, a leg, a nose, a kidney, your children, your siblings, your siblings-in-law, a boat, a lot of money, the London Borough of Haringey, the Eiffel Tower, your 1st cousins, a pool, Poole, a guy named Paul, Long Island, your life savings, nuclear launch codes, another lego set, thirteen domestic cats (Scottish Fold), most of your house, Birmingham, AL, your daily income, everyone who died in the Napoleonic Wars, $30,000,000,000,000,000,000,000,000,000 and £30,000,000,000,000,000,000,000,000,000, Zimbabwe, Lesotho, Angola, Namibia, Ethiopia, Mauritania, Canada, Cuba, Jamaica, The Bahamas, Georgia (country), Georgia (US state), every single person from Bosnia and Herzegovina and your time. Luckily, it doesn't.
    1. Simplify network topology by connecting only one end-device to the TP-Link device. DO NOT connect any other devices like modem or server because those may have an impact on the running of web-based management server of the TP-Link or your end-device.
    1. This is a terrible idea. At least if there's no way to opt out of it! And esp. if it doesn't auto log out the original user after some timeout.

      Why? Because I may no longer remember which device/connection I used originally or may no longer have access to that device or connection.

      What if that computer dies? I can't use my new computer to connect to admin UI without doing a factory reset of router?? Or I have to clone MAC address?

      In my case, I originally set up via ethernet cable, but after I disconnected and connected to wifi, the same device could not log in, getting this error instead! (because different interface has different mac address)

    1. It is possible to use values defined via v: option or X-Mailgun-Variables in your templates. However if you do so, the variables are included in the delivered message via the X-Mailgun-Variables header. If this is not desired, use the t:variables option or X-Mailgun-Template-Variables header instead.

      Why are they included in a header? Indeed that is not desired. So why not just not do that? Why is it different if you use t:variables? Why the inconsistency?

    2. To help you better understand the configuration possibilities and potential issues, take a look at the following table. Take into account the type of threat you are concerned with when making your decision on how to configure sending settings.
    1. When configuring SMTP settings in an after_initialize block, the settings aren't picked up by ActionMailer. This leads to runtime errors, since ActionMailer tries the default settings.
    2. This still seems like a bug, as the expected behavior doesn't occur and it's difficult (for someone unfamiliar with the inner workings of ActionMailer) to debug. I spent a good half an hour figuring out the work around, so I'm trying to prevent others from experiencing the same thing.
    1. YAML parsing is normally considered hard (complicated as the syntax is complex). With all due respect, personally I can adhere to that in part, the YAML specification appears to be at (isolated) places hard to read despite me self-imagined being trained over decades into reading publicly available specifications (in not my first language). To be fair, it is one of the very few specs that has graphics and by the nature of its formulation, compilers are hard to read as well.
    2. JSON is a similar, perhaps even more popular, format (and almost[!] a subset of YAML 1.2).

      almost eh?

    1. Compose V2 has been re-written in Go, which improves integration with other Docker command-line features, and allows it to run natively on macOS on Apple silicon, Windows, and Linux, without dependencies such as Python.
    2. Introduction of the Compose specification makes a clean distinction between the Compose YAML file model and the docker-compose implementation.
    1. While this offers flexibility to address many operator use cases, it makes simple use cases, like the developer use case, more complicated to express than they need to be.

      annotation meta: may need new tag: - developer use case - more complicated to express than they need to be.

    2. Projects like Kompose or Okteto Stacks show how the simpler Compose model can be translated into Kubernetes API payloads
    3. platform-agnostic
    4. make the Compose file the source of truth for development and deployment
    1. This variable supports multiple Compose files separated by a path separator (on Linux and macOS the path separator is :, on Windows it is ;). For example: COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml.
    2. The path separator can also be customized using COMPOSE_PATH_SEPARATOR.
    1. the main feature I miss is to be able to declare abstract services (that should never be runned but could be used to group common properties of services for convenience).
    2. I understand that multiple -f options fits almost the bill, but it doesn't always work. For example, I rather often change the name of the abstract service into something that is more meaningful in the context of the project at hand. This is something that the overriding that occurs with multiple -f options does not support.
    3. I understand that multiple -f options fits almost the bill, but it doesn't always work. For example, I rather often change the name of the abstract service into something that is more meaningful in the context of the project at hand. This is something that the overriding that occurs with multiple -f options does not support. I would not mind loosing the exact extends though, as long as their is some other way to "instantiate" an abstract service in a file.
    4. # Due to lack of "expressivity" in Compose, we define our own couple of service # "pseudo-types": # # - image-only services (name: *-image) # # The only goal of these is to build images. No other services build images. # # These have entrypoint overridden to exit immediately. # # - base services (name: *-base) # # These contain common configuration and are intended to be extended. # # Their command (not entrypoint, to keep the original one) is overridden to # exit immediately. Service must support a command to exit immediately. # # - task services (name: *-task) # # These are intended for running one-off commands. # # Their default command is overridden to exit immediately. Service must # support a command to exit immediately. # # - "real" services # # These are actual services that stay up and running.
    1. Flatpaks are comfortable for users. It does not matter if you're on Debian, Linux Mint or Fedora. It won't break your system as aplications eg. from ppas etc. Distributions are not coming with updates of Audacity, so installations of it are a big problem. Flatpaks solve it...
    2. I have yet to see a Snapd or Flatpak build of Audacity that I'm happy with. Those builds are beyond our control as they are made by 3rd parties. I do find it mildly annoying that Flatpak direct users that have problems with their builds to us.

      annotation meta: may need new tag: the runaround?

    1. Indeed, but the proliferation of general purpose keyboards with OS/2 logo keys has never come to pass... I think most of the keys are either windoze or half-eaten apples...
    1. It could also just be for clarity’s sake, since truck could mean a pick-up truck (or some other type of truck), and tractor could refer to a farm tractor (or some other type of tractor).

      Calling it a semi-truck disambiguates since "truck" and "tractor" are too ambiguous.

    1. We can’t tell you exactly who your administrator is. But here are ideas of who to ask.

      We can’t tell you...

    1. interval values can be written using the following verbose syntax: [@] quantity unit [quantity unit...] [direction] where quantity is a number (possibly signed); unit is microsecond, millisecond, second, minute, hour, day, week, month, year, decade, century, millennium, or abbreviations or plurals of these units
    1. has_scope :category do |controller, scope, value|  value != 'all' ? scope.by_category(value) : scope end
    2. Note: it is not possible to apply a boolean scope with just the query param being present, e.g. ?active, that's not considered a "true" value (the param value will be nil), and thus the scope will be called with false as argument. In order for the scope to receive a true argument the param value must be set to one of the "true" values above, e.g. ?active=true or ?active=1.

      Is this behavior/limitation part of the web standard or a Rails-specific thing?

    1. Let’s say, you’ve set up the list-unsubscribe header to you email campaign. Check out whether it works by sending an email to a test inbox. For Gmail, you’ll see the unsubscribe option in the header right next to the sender name
    1. Easy to scan and understand what’s discussed in the space. Fewer distractions to help you focus on topics you care about. Easy to browse topics because they’re all in one place in the thread navigation panel. Thread replies don’t interrupt the main conversation. You can toggle history on and off.
    2. You can find some benefits and limitations of each kind of space organization below.
    1. The only negative to this method is that it may not ALWAYS work. If the data is faulty, or the link is inaccurately provided by the sender, Gmail won’t be able to recognise and include the unsubscribe button in Gmail.
    2. Most mailing list providers will encourage you to insert a mailto and URL within the header of your emails, or they will be automatically provided.
    3. You may find this link isn’t available straight away, after a few emails one should appear, this is a common technique with mailing list providers.
    4. and the link sometimes isn’t always supported by Gmail

      Any link should work just fine, shouldn't it?

    1. Email addresses sometimes get reassigned to a different person. For example, employment changes at a company can cause an address used for an ex-employee to be assigned to a new employee, or a mail service provider (MSP) might expire an account and then let someone else register for the local-part that was previously used. Those who sent mail to the previous owner of an address might not know that it has been reassigned. This can lead to the sending of email to the correct address but the wrong recipient. This situation is of particular concern with transactional mail related to purchases, online accounts, and the like.
    2. This can lead to the sending of email to the correct address but the wrong recipient.
    1. Errors-To is deprecated, so mail servers will typically ignore this header - most servers will bounce will to the 'envelope sender'. This is the email address that your mail client sends as part of the connection to the SMTP server (not necessarily the From address - though it typically is the same).
    1. This is where ngrok comes into play. It’s a free tool that you can download and run on your dev box. They describe themselves as a secure tunnel to localhost, and it’s just that. It’s as simple as running ngrok http 3000 to forward port 3000 (or any port) to a public ngrok address.

      ngrok

    2. goto
    3. It’s as simple as running ngrok http 3000 to forward port 3000 (or any port) to a public ngrok address.

      We're not forwarding local port 3000 to a public ngrok address — we're doing it in the opposite direction, as the previous sentence just (correctly) stated:

      a secure tunnel to localhost

    4. You can get around this by forwarding your web server’s port on your router and then use your public IP address as the webhook URL but that’s super annoying, exposes your public IP address and it will very likely change because most home grade cable / DSL connections have dynamic IP addresses.Not only that, but some services require that you respond to webhooks over HTTPS, so now you would be responsible for setting up HTTPS too, when really all you want to do is test a webhook in development.
    5. Webhooks are a really powerful concept. They let you integrate with third party services in a very easy way and you can do it without having to constantly pull information from a service.
    1. Postmark separates email traffic through Message Streams, meaning that transactional and broadcast traffic never intersects in Postmark, including IP ranges. This is a longstanding best practice for ensuring optimal deliverability. Transactional message streams are for messages that are usually unique and triggered by a user action like a password reset, opted-into weekly digest, or receipts. Transactional streams do not support bulk messages. Broadcast message streams are for bulk messages that sent to multiple recipients at once like announcements, newsletters, or other application email.
    2. API TypeMailgun API NamePostmark API NameSending EmailsMessagesEmailManaging SuppressionsSuppressionsSuppressionsManaging TemplatesTemplatesTemplatesManaging Sending SettingsServerManaging ServersServersManaging Sent EmailsEventsMessagesManaging Inbound EmailsMessages, EventsMessagesManage Inbound Processing SettingsRoutesManage email domains you can send fromDomainsDomains
    1. The best at transactional email because we never let them mix with bulk messages. You might say that Postmark has serious street cred with inbox providers. To protect the delivery of your transactional emails, it’s crucial to separate them from your bulk or promotional emails. With Message Streams, we’ve built a parallel but completely separate sending infrastructure for these two different types of emails. We don’t let them mix. Ever.
    1. I like how they show -18% -30% over 12-month and 24-month so you can see your savings reward for making longer commitments.

    1. Before, you could send unlimited emails to your lists. This was a huge positive for MailChimp, and it attracted tens of thousands of new customers. Now, they have set limits in an attempt to force users to upgrade. It makes dollar and cents but doesn’t make common sense. It’s alienating a lot of users and hurting their reputation.
    2. Now, they charge by a new metric: audiences. And your audiences also include unsubscribed emails! So, even if someone in your list has unsubscribed, they are still counted in your audience.
    1. With Mailgun, you'll need to upgrade to a dedicated IP or "managed email service" and pay extra for "better deliverability." At Postmark, great deliverability isn't an up-charge. It's simply included, and we share live delivery data so you can judge for yourself.
    1. We will also run into some issues when we consider adding new channels to Service Desk like an API. We should have a streamlined process of rendering notes (messages) etc. Having a base64 image (or even attachment) in mail but not in the API might be inconsistent and also adds a lot of code that needs to be maintained.
    1. Dilemma: Do I use this unofficial library with its really nice idiomatic API or the official library (https://github.com/mailgun/mailgun-ruby) with its inferior API?

      I wish this one was still/better maintained because I'd much rather use this API, like: @mailgun.lists.create "devs@your.mailgun.domain" @mailgun.lists.list @mailgun.lists.find "devs@your.mailgun.domain"

      but it's not maintained, and looks like it doesn't have the word events in the source at all, so it's missing any way to use the Events API. :(

    1. Include one or both of these headers in your messages:

      Actually, if you include List-Unsubscribe-Post, then you MUST include List-Unsubscribe (both).

      According to https://www.rfc-editor.org/rfc/rfc8058#section-3.1,

      A mail sender that wishes to enable one-click unsubscriptions places one List-Unsubscribe header field and one List-Unsubscribe-Post header field in the message. The List-Unsubscribe header field MUST contain one HTTPS URI. It MAY contain other non-HTTP/S URIs such as MAILTO:. The List-Unsubscribe-Post header MUST contain the single key/value pair "List-Unsubscribe=One-Click".

    2. List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: <https://solarmora.com/unsubscribe/example>
    3. Here are some recommended unsubscribe methods: Include a prominent link in the message that takes recipients to a page for unsubscribing. Let recipients review the individual mailing lists they’re subscribed to. Let them unsubscribe from lists individually, or all lists at once. Automatically unsubscribe recipients who have multiple bounced messages. Periodically send a confirmation message to recipients to make sure they still want to get your messages.
    4. Let recipients easily unsubscribe Always give recipients a way to unsubscribe from your messages. Make unsubscribing easy. Letting people opt out of your messages can improve message open rates, click-through rates, and sending efficiency.
    5. Make sure recipients can easily subscribe
    1. But anti- spam software often fetches all resources in mail header fields automatically, without any action by the user, and there is no mechanical way for a sender to tell whether a request was made automatically by anti-spam software or manually requested by a user. To prevent accidental unsubscriptions, senders return landing pages with a confirmation step to finish the unsubscribe request. A live user would recognize and act on this confirmation step, but an automated system would not. That makes the unsubscription process more complex than a single click.

      HTTP: method: safe methods: GETs have to be safe, just in case a machine crawls it.

    2. Many mail systems allow recipients to report mail as spam or junk, and mail streams from senders whose mail is often reported as junk tend to have poor deliverability. Hence, the mailers want to make it as easy as possible for recipients to unsubscribe; if an unsubscription process is too difficult, the recipient's alternative is to report mail from the sender as junk until the mail no longer appears in the recipient's inbox.
    3. Operators of recipient mail systems are aware that their users do not make a clear distinction between unsubscription and junk.